比赛链接:这里  
  OP 
好多大佬哦~
  A 切蛋糕 
这道题是特判题(SpecialJudge),第一眼没看见,读完题就决定放了。
由于宽松的步数限制,可以暴力做,即先通过2047次切割把蛋糕切为2048份,即可保证分配时误差值小于 1 / 1024。再找出可行的 c 满足 fabs( c / 2048 - 1 / k ) <= 1 / 1024,即为给每份包装进 c 个 1 / 211 。
注:经测试,蛋糕可以有剩余。
//标准做法以后再补(flag)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include  <bits/stdc++.h>  using  namespace  std;#define  ll long long   int  main  ()  {     int  k,two=1 ,i,j;     cin>>k;     for (i=1 ; i<=2048 ; i++)     {         if (fabs ((double )i/2048.0 -1.0 /k)<=1.0 /1024 )break ;     }     int  c=i;     printf ("%d\n" ,2047 +k);     for (i=0 ; i<=10 ; i++)     {         for (j=1 ; j<=two; j++)             printf ("1 %d\n" ,i,cou++);         two*=2 ;     }     for (j=1 ; j<=k; j++)     {         printf ("2 %d" ,c);         for (i=1 ; i<=c; i++)printf (" 11" );         printf ("\n" );     }     return  0 ; }
 
  B 小宝的幸运数组 
用 a[ i ] 表示从第一项加到第 i 项的和,则区间 [ i , j ] 的和为 a[ j ] - a[ i - 1 ] 。
若区间 [ i , j ] 的和满足能被 k 整除,则有 ( a[ j ] - a[ i - 1 ] ) % k ==0, 
即 a[ j ] % k == a[ i - 1 ] % k, 
所以此问题等价为找出 a[ i ] % k 相等的最远距离。 
O( k n2  )遍历显然不现实,我们可以对 [ 0 , k - 1 ] 的每一个数存下最前位置和最后位置,再遍历 [ 0 , k - 1 ] 找出左右距离最远的。
求余对四则运算封闭 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include  <bits/stdc++.h>  using  namespace  std;#define  ll long long #define  N 100005    ll a[N];int  main  ()  {     int  t;     cin>>t;     while (t--)     {         int  b[100005 ]={0 },l[100005 ]={0 },r[100005 ]={0 };         int  n,k,i,g,a=0 ,m=0 ;         cin>>n>>k;         b[0 ]=1 ;l[0 ]=0 ;         for (i=1 ;i<=n;i++)         {             scanf ("%d" ,&g);             a+=g;             a%=k;             if (!b[a]){l[a]=i;b[a]++;}             else {r[a]=i;b[a]++;}         }         for (i=0 ;i<k;i++)         {             if (b[i]>=2 &&r[i]-l[i]>m)             m=r[i]-l[i];         }         if (m)printf ("%d\n" ,m);         else  printf ("-1\n" );     }     return  0 ; }
 
  C 	上进的凡凡 
首先依题意,每个数构成的长度为一的数组均为nice的。
若某数大于等于前数,则标注成1,否则标记为0,统计每段连续1的长度,对于长度为 n 的连续1,代表了一段长度为 n + 1 的非降数组,此数组中长度大于等于二的子数组有 n * ( n - 1 ) / 2 个。
累加每一段非降数组的子数组个数,再加上总共的元素个数,即为结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include  <bits/stdc++.h>   using  namespace  std;  int  main ()  {     int  a[100005 ]={0 };     int  n,i,j,c;     long  long  ans=0 ;     cin>>n;     for (i=1 ;i<=n;i++)scanf ("%d" ,&a[i]);     for (i=n;i>=2 ;i--)if (a[i]>=a[i-1 ])a[i]=1 ;else  a[i]=0 ;     a[1 ]=0 ;     int  l,r;     l=1 ,r=1 ;     ans=n;     while (l!=n)     {                  while ((!a[l+1 ])&&l<=n)l++;         r=l+1 ;         while (a[r+1 ]&&r<=n)r++;         if (l<=n&&r<=n){         int  len=r-l+1 ;         ans+=(long  long )len*(len-1 )/2 ;         l=r+1 ;}         if (l>n)l=n;     }     printf ("%lld" ,ans);     return  0 ; }
 
  D Seek the Joker I 
巴什博弈
也可以现推: 
先手者抽牌+后手者抽牌 为一轮 
若保证先手者必赢,则最后一轮开始时需满足桌面有 1 < n <= k + 1 张牌,先手者取 n - 1 张,后手者必输; 
则倒数第二轮开始时,需满足桌面有 k + 2 < n <= 2 * k + 2 张牌,先手者取至剩 k + 2 张,无论后手者如何取,均可满足先手者必赢的最后一轮条件; 
同理,倒数第三轮开始时,需满足桌面有 2 * k + 3 < n <= 3 * k + 3 张牌,先手者取至剩  2 * k + 3 张,无论后手者如何取,均可满足先手者必赢的最后一轮条件;
以此类推,若 n 满足存在正整数 a 使得 ( a - 1 ) * k + a < n <= a * k + a ,则先手者必赢,化简后则等价为 ⌈ n / ( k + 1 ) ⌉ * ( k + 1 ) - k < n。( ⌈ n / ( k + 1 ) ⌉ 即为 a )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include  <bits/stdc++.h>  using  namespace  std;int  main ()  {     int  t;     cin>>t;     while (t--)     {         int  n,k;         scanf ("%d%d" ,&n,&k);         if (ceil (1.0 *n/(k+1 ))*(k+1 )-k<n)         printf ("yo xi no forever!\n" );         else  printf ("ma la se mi no.1!\n" );     }     return  0 ; }
 
补充:也可以说 若 n 满足存在正整数 a 使得 n = ( a - 1 ) * k + a ,等价于 ( n - 1 ) / ( k + 1 )为整数时,先手必输 
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include  <bits/stdc++.h>  using  namespace  std;int  main ()  {     int  t;     cin>>t;     while (t--)     {         int  n,k;         scanf ("%d%d" ,&n,&k);         if ((n-1.0 )/(k+1.0 )-(int )((n-1.0 )/(k+1.0 ))>0.000001 )         printf ("yo xi no forever!\n" );         else  printf ("ma la se mi no.1!\n" );     }     return  0 ; }
 
  E Seek the Joker II 
威佐夫博弈 
这个不太好现推了,走结论吧。
( a < b ) 
( sqrt(5.0) + 1 ) * ( b - a ) / 2 = a 时,先手必输。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <bits/stdc++.h>  #define  ll long long using  namespace  std;int  main ()  {     double  mysticalConstant = (1.0 +sqrt (5.0 ))/2.0 ;     int  T;     cin>>T;     while (T--)     {         int  n,x;         cin>>n>>x;         int  a=x-1 ,b=n-x;         if (a>b) swap (a,b);         int  temp = (b-a)*mysticalConstant;         if (temp!=a) cout<<"yo xi no forever!\n" ;         else  cout<<"ma la se mi no.1!\n" ;     }     return  0 ; }
 
  F 成绩查询ing 
需要构建两组映射:名字与个人信息,成绩与名字 
这里多构建了一组:名字与序号(nn),序号与个人信息(stu),成绩与名字(ms)
成绩对应的名字用set存可以直接按字典序排列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include  <bits/stdc++.h>  using  namespace  std; map<int ,set<string> >ms; set<string>::iterator it; map<string,int >nn;struct  stud  {     int  gra,sex,num;      }stu[100005 ];int  main ()  {     int  n,i;     string ge;       cin>>n;     for (i=1 ;i<=n;i++)     {         cin>>ge;         nn[ge]=i;         scanf ("%d%d%d" ,&stu[i].gra,&stu[i].sex,&stu[i].num);         ms[stu[i].gra].insert (ge);     }     int  t,o;     cin>>t;     while (t--)     {         scanf ("%d" ,&o);         if (o==1 )         {             cin>>ge;             printf ("%d %d %d\n" ,                    stu[nn[ge]].gra,stu[nn[ge]].num,stu[nn[ge]].sex);         }         else          {             scanf ("%d" ,&o);             if (!ms[o].empty ())             {                 for (it=ms[o].begin ();it!=ms[o].end ();it++)                 {                     printf ("%s\n" ,(*it).c_str ());                 }             }         }     }     return  0 ; }
 
  G 贪吃的派蒙 
先找出派蒙的位置(pmi),计算出派蒙左边的人一轮下来所要吃的最少数量ami和最多数量amx,
依靠 ami < k && amx + pmn >= k 判断第一次轮到派蒙时能不能被派蒙吃尽,如果不能,总量减去派蒙吃掉的(pmn)后,每轮ami与amx加上派蒙外所有人的最小值与最大值,再进行比较。amx > k 为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include  <bits/stdc++.h>  using  namespace  std;#define  ll long long   int  main  ()  {     int  t;     cin>>t;     while (t--)     {         int  n,k,pmi,pmn=0 ,i,f=0 ;         int  r[100005 ]= {0 };         cin>>n>>k;         for (i=1 ; i<=n; i++)         {             scanf ("%d" ,&r[i]);             if (r[i]>pmn)             {                 pmn=r[i];                 pmi=i;             }         }         ll ami=pmi-1 ,amx=0 ;         for (i=1 ; i<pmi; i++)amx+=r[i];         if (ami<k&&amx+pmn>=k)f=1 ;         else          {             while (amx<=k)             {                 k-=pmn;                 ami+=n-1 ;                 for (i=pmi+1 ; i<=n; i++)amx+=r[i];                 for (i=1 ; i<pmi; i++)amx+=r[i];                 if (ami<k&&amx+pmn>=k)                 {                     f=1 ;                     break ;                 }             }         }         if (f)printf ("YES\n" );         else  printf ("NO\n" );     }     return  0 ; }
 
  H 数羊 
打表找规律
m = 0 时,A( n , 0 ) = n + 2 ;(n = 1 时特判 A( 1, 0 ) = 2 ) 
m = 1 时,A( n , 1 ) = 2 * n ; 
m = 2 时,A( n , 2 ) = 2n 。
m = 2 时需要用到快速幂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <bits/stdc++.h>  #define  ll long long const  ll mod=998244353 ;using  namespace  std;ll qm (ll m)   {     ll ans=1 ,n=2 ;     while (m)     {         if (m&1 )ans=ans*n%mod;         n=n*n%mod;         m>>=1 ;     }     return  ans%mod; }int  main ()  {     ll t,n,m;     cin>>t;     while (t--)     {         scanf ("%lld%lld" ,&n,&m);         if (m==0 )         {             if (n==1 )printf ("2\n" );             else  printf ("%lld\n" ,n+2 );         }         else  if (m==1 )         {             printf ("%lld\n" ,2 *n);         }         else  printf ("%lld\n" ,qm (n));     }     return  0 ; }
 
  I 买花 
若第一天买 a 朵,则第二天有 a * 11(B) 朵,第三天有 a * 111(B) 朵,……,第十五天有 a * 111 1111 1111 1111(B) 朵,则直接遍历[ 11 , 111 , … , 111 1111 1111 1111 ](B),目标量能否被其中元素整除,若能则可行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include  <bits/stdc++.h>  using  namespace  std;  int  main ()  {     int  k[]={3 ,7 ,15 ,31 ,63 ,127 ,255 ,511 ,1023 ,2047 ,4095 ,8191 ,16383 ,32767 };     int  i,n,t;     cin>>t;     while (t--)     {         scanf ("%d" ,&n);         for (i=0 ;i<=13 ;i++)             if (n%k[i]==0 )break ;         if (i==14 )printf ("N0\n" );         else  printf ("YE5\n" );     }     return  0 ; }
 
  J 这是一题简单的模拟 
可以直接用二维数组建图,检验题给数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include  <bits/stdc++.h>  using  namespace  std;  int  main ()  {     int  n,m,f,t,co,a,mi=0x7fffffff ,i;     cin>>n>>m;     int  r[302 ][302 ]= {0 };     while (m--)     {         scanf ("%d%d%d" ,&f,&t,&co);         r[f][t]=co;         r[t][f]=co;     }     cin>>a;     int  p[302 ]= {0 },c[302 ]= {0 },g,fl;     while (a--)     {         fl=1 ;         memset (p,0 ,sizeof  p);         memset (c,0 ,sizeof  c);         cin>>g;         for (i=1 ; i<=g; i++)         {             scanf ("%d" ,&p[i]);             if (!c[p[i]])c[p[i]]=1 ;             else  fl=0 ;         }         if (g!=n||!fl)continue ;         fl=1 ;         f=0 ;         int  cou=0 ;         for (i=1 ; i<=g&&fl; i++)         {             if (r[f][p[i]])cou+=r[f][p[i]];             else  fl=0 ;             f=p[i];         }         if (r[f][0 ]&&fl)cou+=r[f][0 ];             else  fl=0 ;         if (fl&&cou<=mi)mi=cou;     }     if (mi<0x7fffffff )printf ("%d" ,mi);     else  printf ("-1" );     return  0 ; }
 
  K 黑洞密码 
字符串处理,注意好对26溢出的处理即可。
注:对于二维数组 a[ 4 ][ 4 ] ,a[ 0 ][ 5 ] 即代表 a[ 1 ][ 0 ],这个在这里很好用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include  <bits/stdc++.h>  using  namespace  std;  int  main ()  {     int  a[4 ][4 ]={0 },in=0 ,ch=0 ,i=0 ,j;     char  c[4 ][4 ],g;     for (i=1 ;i<=32 ;i++)     {         scanf ("%c" ,&g);         if (g>='0' &&g<='9' )a[0 ][in++]=g-'0' ;         else  c[0 ][ch++]=g;     }     for (i=0 ;i<=3 ;i++)     {         for (j=0 ;j<=3 ;j++)         {             if (c[i][j]>='A' &&c[i][j]<='Z' )             {                 if (c[i][j]+a[i][j]>'Z' )c[i][j]='a' +c[i][j]+a[i][j]-'Z' ;                 else  c[i][j]+=a[i][j];             }             else              {                 if (c[i][j]+a[i][j]>'z' )c[i][j]='A' +c[i][j]+a[i][j]-'z' ;                 else  c[i][j]+=a[i][j];             }         }         for (j=3 ;j>=0 ;j--)printf ("%c" ,c[i][j]);     }     return  0 ; }
 
  L 建立火车站 
二分,对于长度,端点值及其右侧均为可行解,故向左取整。
注:存在 k = 0 的测试组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include  <bits/stdc++.h>  using  namespace  std;  int  main ()  {     long  long  a[100005 ];     long  long  n,k,i;     cin>>n>>k;     for (i=1 ; i<=n; i++)scanf ("%lld" ,&a[i]);     sort (a+1 ,a+n+1 );     long  long  l=1 ,r=a[n]-a[1 ]+5 ;     while (l<r)     {         long  long  mid=l+r>>1 ;         long  long  cou=0 ;         for (i=2 ; i<=n; i++)         {                          {                 cou+=(a[i]-a[i-1 ]-1 )/mid;             }         }         if (cou<=k)r=mid;         else  l=mid+1 ;     }     printf ("%lld" ,l);     return  0 ; }
 
  ED 
做到最后莫划水,打表有惊喜。
打表天下第一!