1. 程式人生 > >2018年全國多校算法寒假訓練

2018年全國多校算法寒假訓練

ike pre 興趣 sca 一個數 include 不能 可能 相同

題目描述

夫夫有一天對一個數有多少位數感興趣,但是他又不想跟凡夫俗子一樣,
所以他想知道給一個整數n,求n!的在8進制下的位數是多少位。

輸入描述:

第一行是一個整數t(0<t<=1000000)(表示t組數據)
接下來t行,每一行有一個整數n(0<=n<=10000000)

輸出描述:

輸出n!在8進制下的位數。
示例1

輸入

3
4
2
5

輸出

2
1
3

思路: 斯特林公式。

斯特林公式(Stirling‘s approximation)是一條用來取n的階乘的近似值的數學公式,求N!的位數:
lnN!=NlnN-N+0.5*ln(2*N*pi) !要想求有多少位,將他換成以10為底便可。利用換底公式得 log10N!=lnN!/ln10=n*lg(n/E) +lg(sqrt(2*n*PI)).把式子取整形加1就是位數!

代碼:

 1 //#include "bits/stdc++.h"
 2 #include "cstdio"
 3 #include "map"
 4 #include "set"
 5 #include "cmath"
 6 #include "queue"
 7 #include "vector"
 8 #include "string"
 9 #include "cstring"
10 #include "time.h"
11 #include "iostream"
12 #include "stdlib.h"
13 #include "algorithm"
14 #define db double
15
#define ll long long 16 #define vec vector<ll> 17 #define Mt vector<vec> 18 #define ci(x) scanf("%d",&x) 19 #define cd(x) scanf("%lf",&x) 20 #define cl(x) scanf("%lld",&x) 21 #define pi(x) printf("%d\n",x) 22 #define pd(x) printf("%f\n",x) 23 #define pl(x) printf("%lld\n",x) 24
#define inf 0x3f3f3f3f 25 #define rep(i, x, y) for(int i=x;i<=y;i++) 26 const int N = 1e6 + 5; 27 const int mod = 1e9 + 7; 28 const int MOD = mod - 1; 29 const db eps = 1e-10; 30 const db PI = acos(-1.0); 31 using namespace std; 32 const db E=2.71828182845; 33 int main() 34 { 35 ll t,n; 36 cl(t); 37 while(t--) 38 { 39 ll ans=1; 40 cl(n); 41 if(n>3){ 42 ans=(n*(log10((db)n/E))+log10(sqrt((db)2.0*n*PI)))/log10(8)+1; 43 } 44 pl(ans); 45 } 46 return 0; 47 }

D 小牛vs小客

題目描述

小牛和小客玩石子遊戲,他們用n個石子圍成一圈,小牛和小客分別從其中取石子,誰先取完誰勝,每次可以從一圈中取一個或者相鄰兩個,每次都是小牛先取,請輸出勝利者的名字(小牛獲勝輸出XiaoNiu,小客獲勝輸出XiaoKe)(1 2 3 4 取走 2 13 不算相鄰)

輸入描述:

輸入包括多組測試數據
每組測試數據一個n(1≤n≤1e9)

輸出描述:

每組用一行輸出勝利者的名字(小牛獲勝輸出XiaoNiu,小客獲勝輸出XiaoKe)
示例1

輸入

2
3

輸出

XiaoNiu
XiaoKe

思路:博弈題目,取石子(七)問題。

思路:假設石子數等於5,如果先者先取一個,那麽後者拿走兩個,將剩下的兩個石子分成兩堆,後者贏。如果先者先取二個,那麽後者取一個使剩下的兩個石子分成兩堆,後者贏。

假設石子數等於6,如果先者先取一個,那麽後者拿走一個,將剩下的石子分成兩段,每段兩個,如果先者再拿兩個,那麽後者贏,如果先者再拿一個,那麽後者再取另一堆中的一個,這樣剩下的兩個石子被分成兩堆, 後者贏。 如果先者先取兩個,那麽後者也取兩個使剩下的兩個石子分成兩堆,後者贏。

所以當先者取走後,後者取走一個或者兩個,將剩下的石子分成對稱的兩段,以此類推,那麽如果石子數大於2後者一定贏。

代碼:

 1 #include <stdio.h>  
 2   
 3 int main (void)  
 4 {  
 5     int n;  
 6     while (scanf("%d", &n) != EOF)  
 7     {  
 8         if(n > 2)  
 9             printf("XiaoKe\n");  
10         else  
11             printf("XiaoNiu\n");  
12     }  
13     return 0;  
14 }  

G:大水題

給出一個數n,求1到n中,有多少個數不是2 5 11 13的倍數。

輸入描述:

本題有多組輸入
每行一個數n,1<=n<=10^18.

輸出描述:

每行輸出輸出不是2 5 11 13的倍數的數共有多少。

示例1

輸入

15

輸出

4

說明

1 3 7 9

思路:

容斥原理:要計算幾個集合並集的大小,我們要先將所有單個集合的大小計算出來,然後減去所有兩個集合相交的部分,再加回所有三個集合相交的部分,再減去所有四個集合相交的部分,依此類推,一直計算到所有集合相交的部分。

代碼:

 1 #include<map>
 2 #include<vector>
 3 #include<queue>
 4 #include<cstdio>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<iostream>
 8 #include<algorithm>
 9 #include<cmath>
10 #define maxn 100010
11 using namespace std;
12 typedef long long ll;
13 #define PI acos(-1.0)
14 int main()
15 {
16     ll n;
17     ios::sync_with_stdio(false);
18     while(scanf("%lld",&n)!=EOF)
19     {
20         ll cnt;
21         cnt=n-(n/2)-(n/5)-(n/11)-(n/13);
22         cnt=cnt+(n/10)+(n/22)+(n/26)+(n/55)+(n/65)+(n/143);
23         cnt=cnt-(n/110)-(n/130)-(n/715)-(n/286);
24         cnt=cnt+(n/1430);
25         cout<<cnt<<endl;
26     }
27     return 0;
28 }

F:

題目描述

共有N堆石子,已知每堆中石子的數量,兩個人輪流取石子,每次只能選擇N堆石子中的一堆取一定數量的石子(最少取一個),取過子之後,還可以將該堆石子中剩余的石子隨意選取幾個放到其它的任意一堆或幾堆上。等哪個人無法取子時就表示此人輸掉了遊戲。註意:一堆石子沒有子之後,就不能再往此處放石子了。

假設每次都是小牛先取石子,並且遊戲雙方都絕對聰明,現在給你石子的堆數、每堆石子的數量,請判斷出小牛能否獲勝。

輸入描述:

可能有多組測試數據(測試數據組數不超過1000)
每組測試數據的第一行是一個整數,表示N(1<=N<=10)
第二行是N個整數分別表示該堆石子中石子的數量。(每堆石子數目不超過100)
當輸入的N為0時,表示輸入結束

輸出描述:

對於每組測試數據,輸出Win表示小牛可以獲勝,輸出Lose表示小牛必然會敗。
示例1

輸入

3
2 1 3
2
1 1
0

輸出

Win
Lose

思路:如果只有一堆石子,則先手必勝.如果有兩堆相同數目的石子,顯然先手必敗,因為對手只需對稱操作即可.
同理可知,如果石子可分為兩組,對應堆石子數相等,如{1,2,3,1,2,3},則先手同樣必敗,於是數目相同的兩堆先可以暫不考慮.
如果有兩堆數目不同的石子,則先手可以使之數目相同,先手必勝.
如果有三堆互不相同的石子,先手可以選擇最大的一堆操作,移除一部分後,使剩下的石子正好補齊剩下兩堆之間的差距,先手必勝.依次類推,先手必敗當且僅當初始時石子數是{1,2,3,1,2,3}這種類型.

代碼:

 1 #include<stdio.h>
 2 int stack[15],C[15];
 3 int main()
 4 {
 5     int N;
 6     while (scanf("%d",&N)!=EOF)
 7     {
 8         if (N==0) return 0;
 9         for (int i=1;i<=N;i++) scanf("%d",&C[i]);
10         for (int i=1;i<=N-1;i++)
11             for (int j=i+1;j<=N;j++)
12             if (C[i]>C[j])
13             {
14                 int tmp=C[i];
15                 C[i]=C[j];
16                 C[j]=tmp;
17             }
18         int T=0;
19         for (int i=1;i<=N;i++)
20         {
21             if (T==0) stack[++T]=C[i];
22             else
23             {
24                 if (stack[T]==C[i]) T--;
25                 else stack[++T]=C[i];
26             }
27         }
28         if (T==0) printf("0\n");
29         else printf("1\n");
30     }
31     return 0;
32 }

2018年全國多校算法寒假訓練