比赛链接:这里 
个人能力有限,有的题目实在知识点欠缺太多,这里是大佬的全题解 
最大公因数,字符串
依照样例来说,很像求n n n l l l l > n 2 l>\frac{n}{2} l > 2 n  n − l n-l n − l g c d ( n , l ) gcd(n,l) g c d ( n , l ) 
循环节上每一位应该取在当位数量最多的字母,以求更改次数最少。
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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;ll gcd (ll a,ll b)  return  b==0 ?a:gcd (b,a%b);}int  main () int  n,l,i,t;char  get[100005 ],ans[100005 ];int  mx[100005 ],cnt[100005 ][26 ];while (t--)scanf ("%d%d" ,&n,&l);if (2 *l>n)l=n-l;else  l=gcd (l,n);scanf ("%s" ,&get);for (i=0 ;i<=l;i++)0 ;for (int  j=0 ;j<26 ;j++)cnt[i][j]=0 ;for (i=0 ;i<n;i++)'a' ]++;if (cnt[i%l][get[i]-'a' ]>mx[i%l])'a' ];for (i=0 ;i<n;i++)printf ("%c" ,ans[i%l]);printf ("\n" );return  0 ;
数学
我们先找规律,依照如下两图
⌊ n / x ⌋ ⌊ n / x ⌋ ⌊ n / x ⌋ ⌊ n / x ⌋ ⌊ n / x ⌋ ⌊ n / x ⌋ 
我们只需要找到这个分界点 a ,如果 x <= a ,即可直接输出x;否则就输出 ⌊ n / a ⌋ − ⌊ n / x ⌋ + a ⌊ n / a ⌋-⌊ n / x ⌋+a ⌊ n / a ⌋ − ⌊ n / x ⌋ + a x 当点的商与 a 点的商的差值 为 a 点后至 x 点有的不同商值的个数,再加上 a 即为 x 之前存在的不同商值的总数。
现在我们要找到这个 a :
用函数 f ( x ) = n / x f(x)=n/x f ( x ) = n / x f ′ ( a ) > = − 1 f'(a)>=-1 f ′ ( a ) > = − 1 f ′ ( x ) = − n / x 2 f'(x)=-n/x^2 f ′ ( x ) = − n / x 2 f ′ ( a ) > = − 1 f'(a)>=-1 f ′ ( a ) > = − 1 n / a 2 < = 1 n/a^2<=1 n / a 2 < = 1 a 2 > = n a^2>=n a 2 > = n a = ⌈ n ⌉ a=⌈\sqrt{n}⌉ a = ⌈ n  ⌉ 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;int  main () int  t;while (t--)int  n,x,sq;scanf ("%d%d" ,&n,&x);sqrt (n);if (sq*sq!=n)sq++;if (x<=sq)printf ("%d\n" ,x);else  printf ("%d\n" ,n/sq-n/x+sq);return  0 ;
bfs,双指针
这道题十分明显是bfs,只不过数据量对建图造成了一定的困难;
对于同行,只需要判断相邻两板的左右缘是否相接;
对于临行,可以通过双指针来判断联通;
由于板与板不重叠的限制,我们可以放心用set存储,不会出现去重,而且lineleft与linerig的相同位置存储的必定是同一块板的数据。
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;int ,int > >linelef[100005 ],linerig[100005 ];int ,int > >::iterator it1,it2,it3,it4;int > con[100005 ];int  n,dis[100005 ];int >que;void  dfs () while (!que.empty ())int  now=que.front ();pop ();for (int  i=0 ;i<con[now].size ();i++)if (!dis[con[now][i]])1 ;push (con[now][i]);int  main () int  i,lin,gl,gr,lmi=100005 ,lma=0 ;for (i=1 ;i<=n;i++)scanf ("%d%d%d" ,&lin,&gl,&gr);insert ({gl,i});insert ({gr,i});min (lmi,lin);max (lma,lin);for (i=lmi;i<=lma;i++)for (it1=linerig[i].begin (),it2=linelef[i].begin (),it2++;it2!=linelef[i].end ();it1++,it2++)if ((*it1).first==(*it2).first)push_back ((*it2).second);push_back ((*it1).second);if (i!=lma)for (it1=linelef[i].begin (),it2=linerig[i].begin (),it3=linelef[i+1 ].begin (),it4=linerig[i+1 ].begin ()end ()&&it3!=linelef[i+1 ].end ();)if ((*it2).first<=(*it3).first)it1++,it2++;else  if ((*it1).first>=(*it4).first)it3++,it4++;else push_back ((*it1).second);push_back ((*it3).second);if ((*it2).first<=(*it4).first)it1++,it2++;else  it3++,it4++;memset (dis,0 ,sizeof  dis);1 ]=1 ;push (1 );dfs ();printf ("%d" ,dis[n]-1 );return  0 ;
此题看起来 k 会有好多个可行取值,但是由于下一次做区间翻转的位置将会比上一次更靠右 的限制,实际上只有一个可行的 k 。
如果 1 在第 i 位( i != 1 ),则唯一的可行 k 为 i ,确定 k 后,持续进行模拟操作即可;
本来担心持续的模拟操作会导致TLE,结果来看时间卡得没有那么严。
//悲:
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;typedef  long  long  ll;int  main () int  n,i,a[100005 ],k=0 ,j,f=1 ;for (i=1 ;i<=n;i++)scanf ("%d" ,&a[i]);for (i=1 ;i<=n;i++)if (a[i]!=i)if (k==0 )for (j=i;j<=n;j++)if (a[j]==i)break ;for (j=i;j<=i+k/2 ;j++)swap (a[j],a[2 *i+k-j]);else  if (i+k>n||a[i+k]!=i){f=0 ;break ;}else  if (a[i+k]==i)for (j=i;j<=i+k/2 ;j++)swap (a[j],a[2 *i+k-j]);if (f==0 )printf ("no" );else  printf ("yes\n%d" ,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 35 36 37 38 #include <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;const  int  N=2e5 +5 ;int ,int >mp;int ,int >::iterator it;int  cot[N];int  main () int  n,m;int  l,r;for (int  i=0 ;i<m;i++){1 ]--;int  linej=0 ,liney=0 ,linet=0 ,ceil (1.0 *n/10 ),y=ceil (1.0 *n/4 ),t=ceil (1.0 *n/2 );int  last=1 ,cnt=0 ,maxx=0 ;for (it=mp.begin ();it!=mp.end ();it++){max (maxx,cnt);for (int  i=maxx;i>=0 ;i--){1 ];if (cot[i]>=j&&!linej)linej=max (1 ,i);if (cot[i]>=y&&!liney)liney=max (1 ,i);if (cot[i]>=t&&!linet)linet=max (1 ,i);' ' <<cot[liney]-cot[linej]<<' ' <<cot[linet]-cot[liney]<<'\n' ;return  0 ;
签到题
找规律,输出内容相同的点 横纵坐标之和奇偶性相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include  <bits/stdc++.h>  using  namespace  std;int  main () int  n,i,j;for (i=0 ;i<n;i++)for (j=0 ;j<n;j++)if ((i+j)&1 )printf ("1" );else  printf ("0" );printf ("\n" );
我们需要处理出每一个 i 的全部质因数再做处理,首先想到的便是分解定理,奈何时间复杂度略大,具体可以参照下面的第二片代码。
同时,用到质因子的地方还有欧拉筛,在欧拉筛中,每一个合数是被其最小质因子筛掉的,我们便可以利用这个性质,递推处理每一个合数。
具体过程如下:
具体实现起来,我们要妥善处理位数,对位数的求取一定要慎重,具体可以参照惨案代码片三
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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;const  ll N = 4000006 ;const  ll M = 1000000007 ;static  int  p[N];static  bool  n[N];static  ll w[N],z[N];int  main () int  i,j,c=0 ;1 ]=1 ,z[1 ]=0 ;for (i=2 ; i<N; i++)if (!n[i])10 ;for (; ten<i; ten*=10 );for (j=0 ; j<c&&i*p[j]<N; j++)1 ;if (i%p[j]==0 )break ;long  long  ans=0 ,n;for (i=2 ;i<=n;i++){printf ("%llu" ,ans);
比赛时我的代码只能大概算到1e6,否则就超时,于是我就阶段打表,每1e6算一个结果,对于 n ,只算 n ~ n/1e6*1e6 这段就OK了。代码贴在下面,仅供参考;
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;const  ll N = 4000006 ;const  ll M = 1000000007 ;static  int  p[N],w[N];static  bool  n[N];long  long  a1=631719342 ,a2=220078001 ,a3=827425989 ;long  long  wf (long  long  a) if (!n[a])return  a;0 ,i;for (i=0 ; p[i]<=sqrt (a); i++)while (a%p[i]==0 )if (a>1 )int  ten=10 ;for (; ten<a; ten*=10 );return  ans;int  main () int  i,j,c=0 ;1 ]=1 ;for (i=2 ; i<=N; i++)if (!n[i])int  ten=10 ;for (; ten<i; ten*=10 );-1 ]=ten;for (j=0 ; j<c&&i*p[j]<=N; j++)1 ;if (i%p[j]==0 )break ;if (n/1000000 ==0 )0 ;for (i=1 ; i<=n; i++)wf (i);else  if (n/1000000 ==1 )for (i=1000001 ; i<=n; i++)wf (i);else  if (n/1000000 ==2 )for (i=2000001 ; i<=n; i++)wf (i);else for (i=3000001 ; i<=n; i++)wf (i);printf ("%lld" ,ans);
//有个同学打了34M的表,交不上去 -_-||
还有一段错误代码,这里对于合数 如果用for求位数,先求位数再取模也不行,只要在过程中历史值进行过取模运算就会改变真实长度,再搭配for求位数结果就是错误的;用成积求位数是,尽管位数本身经过取模,但仍是真实位数的取模值。惨案贴上来供批判
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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;const  ll N = 4000006 ;const  unsigned  long  long  M = 1000000007 ;static  int  p[N];static  bool  n[N];static  unsigned  long  long  w[N],z[N];int  main () int  i,j,c=0 ;1 ]=1 ,z[1 ]=0 ;for (i=2 ; i<N; i++)if (!n[i])10 ;for (; ten<i; ten*=10 );for (j=0 ; j<c&&i*p[j]<N; j++)1 ;unsigned  long  long  ten=10 ;for (; ten<z[i*p[j]]; ten*=10 );if (i%p[j]==0 )break ;unsigned  long  long  ans=0 ,n;for (i=2 ;i<=n;i++){printf ("%llu" ,ans);
构造
首先计算可知,n <= 27 时,C( n , 3 ) < n2 log2 n ,也就是说,此时输出的前 27 项不能含有任何合法组,这里可以用斐波那契数列来解决。
n > 27 时,即可认为 n2 ⌊ log2 n⌋ 中的 ⌊ log2 n⌋ 是第一个元素的遍历量,n = 105  时, ⌊ log2 n⌋ = 16 ,也就是说此时前16项的任意一项无法与后面的元素组成任何合法组。所以说,为了便于输出,只需要保证第 17 项及之后的每一位均小于等于 第一项/2。在前一种情况中,因为前 27 项均无合法组,所以第 27 项及之后保证每一位均小于等于 第一项/2 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include  <bits/stdc++.h>  using  namespace  std;int  main () int  f[30 ]={1 ,1 },a[100005 ],i;for (i=2 ;i<=28 ;i++)-1 ]+f[i-2 ];for (i=1 ;i<=27 ;i++)a[i]=f[i];for (i=28 ;i<=100000 ;i++)a[i]=1 ;int  n;for (i=1 ;i<=n;i++)printf ("%d " ,a[i]);