2021.10.20

T1:取石子游戏

Problem:

小林和亮亮正在玩一个取石子的游戏。
石子一共有 n 堆,其中第 i 堆恰好有 i 粒石子。小林先取,亮亮后取,并且两人依次轮流取石。每一次取石子的人可以选择任意一堆还未被取完的石子,并取走这一堆中任意多粒石子(注意,不能一粒石子也不取,也不能同时在多堆石子中取石)。最终,无石可取的人为败。
小林和亮亮都十分聪明,他们的每次取石都会采取最优策略。在经过多次游戏后,小林发现了先手必胜的条件,但他不满足于此,他想知道,在知道石子的堆数 n 后,他第一次取石有多少种方式可以获胜。

Code:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 struct nim{
  4     int len,value[1010];
  5     nim(){len=1;memset(value,0,sizeof(value));}
  6     nim operator =(const char* s){
  7         len=strlen(s);
  8         memset(value,0,sizeof(value));
  9         for(int i=0;i<len;i++){
 10             value[i]=s[len-i-1]-48;
 11         }
 12         return *this;
 13     }
 14     nim operator =(const int& x){
 15         char s[1010];
 16         sprintf(s,"%d",x);
 17         *this=s;
 18         return *this;
 19     }
 20     nim operator +(const nim& x) const{
 21         nim y;
 22         y.len=max(len,x.len);
 23         for(int i=0;i<len;i++) y.value[i]=x.value[i]+value[i];
 24         int k=0;
 25         for(int i=0;i<y.len;i++){
 26             k+=y.value[i];
 27             y.value[i]=k%10;
 28             k/=10;
 29         }
 30         if(k>0){
 31             y.value[y.len]=k;
 32             y.len++;
 33         }
 34         return y;
 35     }
 36     nim operator += (const nim& x){
 37         *this=*this+x;
 38         return *this;
 39     }
 40     nim operator /= (const int& x){
 41         int p=0;
 42         for(int i=len-1;i>=0;i--){
 43             p=p*10+value[i];
 44             value[i]=p/x;
 45             p%=x;
 46         }
 47         if(!value[len-1]) len--;
 48         return *this;
 49     }
 50     nim operator *= (const int& x){
 51         int p=0;
 52         for(int i=0;i<len;i++){
 53             p+=value[i]*x;
 54             value[i]=p%10;
 55             p/=10;
 56         }
 57         if(p>0){value[len]=p;len++;}
 58         return *this;
 59     }
 60     bool operator <=(const nim& x) const{
 61         if(len!=x.len) return len<x.len;
 62         for(int i=len-1;i>=0;i--){
 63             if(value[i]<x.value[i]) return true;
 64             if(value[i]>x.value[i]) return false;
 65         }
 66         return true;
 67     }
 68     nim operator -=(const nim& x){
 69         for(int i=0;i<len;i++) value[i]-=x.value[i];
 70         for(int i=0;i<len;i++) if(value[i]<0){value[i]+=10;value[i+1]--;}
 71         while(len>1&&value[len-1]==0) len--;
 72         return *this;
 73     }
 74 }a,b;
 75 void writeint(nim x){
 76     for(int i=x.len-1;i>=0;i--) printf("%d",x.value[i]);
 77     printf("\n");
 78 }
 79 int main(){
 80     int T;
 81     scanf("%d",&T);
 82     while(T--){
 83         char s[1010];
 84         scanf("%s",s);
 85         int n=strlen(s);
 86         if((s[n-1]-48)%2){
 87             a=s,b=1,a+=b;
 88             int k=s[n-1]-48+1;
 89             if(n>1) k+=(s[n-2]-48)*10;
 90             if(!(k%4)){printf("0\n");continue;}
 91             a/=2;
 92             writeint(a);
 93             continue;
 94         }
 95         else{
 96             b=1;
 97             a=s;
 98             while(b<=a) b*=2;
 99             b/=2;
100             a-=b;
101             b=1;
102             a+=b;
103             writeint(a);
104         }
105     }
106     return 0;
107 }

T2:魔数

Problem:

小林和亮亮是好朋友。小林有一个幸运数字 a,亮亮有一个幸运数字 b。一个数字称之为“幸运数”当且仅当它只由 a 和 b 组成。小林称一个数为“魔数”,当且仅当这个数各数位之和为“幸运数”,且这个数字本身也是“幸运数”。
举个例子:小林的幸运数字为 2,亮亮的幸运数字为 6,那么 23 不是“幸运数”,而 26、222 是“幸运数”。进一步,222 是“魔数”(因为 2+2+2=6),而 26不是“魔数”(因为 2+6=8)。
亮亮想要知道,有多少个 n 位的“魔数”(一个 n 位数不包含前导 0),由于这个数字会很大,所以亮亮只关心这个数模 1000000007(10^9+7,是一个质数)的结果。

Code:

 1 #include<bits/stdc++.h>
 2 #define modd 1000000007
 3 using namespace std;
 4 long long q_pow(long long x,long long v){
 5     long long ans=1;
 6     while(v){
 7         if(v&1){
 8             ans*=x;
 9             ans%=modd;
10         }
11         x*=x;
12         x%=modd;
13         v>>=1;
14     } 
15     return ans;
16 }
17 long long fac[1000010],inv[1000010];
18 int a,b,n;
19 void init(){
20     fac[0]=1;
21     for(int i=1;i<=1000000;i++){
22         fac[i]=fac[i-1]*i%modd;
23     }
24     inv[1000000]=q_pow(fac[1000000],modd-2);
25     for(int i=999999;i>=0;i--){
26         inv[i]=inv[i+1]*(i+1)%modd;
27     }
28 }
29 bool is(long long x){
30     while(x){
31         int now=x%10;
32         if(now!=a&&now!=b) return 0;
33         x/=10;
34     }
35     return 1;
36 }
37 int main(){
38     init();
39     long long ans=0;
40     cin>>a>>b>>n;
41     for(int i=0;i<=n;i++){
42         long long now=a*i+b*(n-i);
43         if(is(now)){
44             ans+=(fac[n]*inv[i])%modd*inv[n-i]%modd;
45             ans%=modd;
46         }
47     }
48     cout<<ans<<endl;
49 }

T3:军训站队

Problem:

小林和亮亮刚入高中,首先就迎来了军训。这一天,他们班的同学正在教官的指导下进行队列练习。
班上总共有 n 位同学,他们站成一排,然而,本该站成一条直线的他们却排成了“一字长蛇阵”。用数学的语言来描述,如果把训练场看成一个平面直角坐标系,第 i 名同学所在位置的横坐标是 i,而所有同学的纵坐标本该是 0(或者任意一个相等的常量),这样就排成了一条直线。当然,由于同学们排的歪歪扭扭,所以第 i 位同学的横坐标依然是 i,而纵坐标却成了Yi (为了简化问题,我们假设所有的坐标都是整数)。
对此,教官当然十分生气,因此他决定下命令调整队伍,使得所有人能够站成一条直线(也即让所有的Yi 相同)。教官的命令总共有三种:
1、除了某一个同学外,其余所有同学向前走一步(向前走一步可理解为Yi 的值加 1,下同);
2、除了某一个同学外,其余所有同学向前走两步;
3、除了某一个同学外,其余所有同学向前走五步。
教官希望他能以最少的命令次数使得所有同学站成一条直线,但是他不会算,于是就让亮亮帮他来计算。亮亮虽然聪明,可是由于班上同学人数众多,他一下子也解决不了这个问题,只能来寻求会编程的你的帮助,你能告诉亮亮答案吗?

Code:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,a[100001],b[100001];
 4 long long ans=0,ss;
 5 int main(){
 6     scanf("%d",&n);
 7     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 8     sort(a+1,a+n+1);
 9     for(int i=n;i>=1;i--) a[i]-=a[1];
10     memcpy(b,a,sizeof(b));
11     for(int j=0;j<5;j++){
12         ans=0;
13         memcpy(a,b,sizeof(b));
14         for(int i=1;i<=n;i++) a[i]+=j;
15         for(int i=1;i<=n;i++){
16             if(a[i]>=5) ans+=(long long)a[i]/5,a[i]%=5;
17             if(a[i]>=2) ans+=(long long)a[i]/2,a[i]%=2;
18             if(a[i]>0) ans+=(long long)a[i],a[i]=0;
19         }
20         if(j==0) ss=ans; 
21         else ss=min(ss,ans);
22     }
23     printf("%lld\n",ss);
24     return 0;
25 }

 

posted @ 2021-10-20 18:42  B_lank  阅读(66)  评论(0编辑  收藏  举报