比赛链接:这里 
肝了两个半小时A,没过……题解 了
最大公约数
任选两数 a,b 做 2*a-b 运算,可以理解成 a + a - b ,即 a 加上两数的差;
此时,对于 a , b 两数,能组成的所有数可以构成一个含 a , b 、公差为 a - b 的等差数列。
那所有可能被加入集合的元素即满足a i + m j ∗ ( a i − a j ) a_i+ m_j * ( a_i - a_j ) a i  + m j  ∗ ( a i  − a j  ) j  可以为计算出的元素值)
枚举显然是不现实的,我们可以使式子更加普适,转化成如下形式a m i n + m ∗ g c d ( a 2 − a 1 , a 3 − a 2 , . . . , a n − a n − 1 ) a_{min}+ m * gcd( a_{2}-a_{1},a_{3}-a_{2},...,a_{n}-a_{n-1}) a m i n  + m ∗ g c d ( a 2  − a 1  , a 3  − a 2  , . . . , a n  − a n − 1  ) 
现在只需算出 gcd 并用 k 与 amin  的差对其取模即可。
我的过程可能不太好理解,可以直接参照sl大佬的题解。
看到标程之前的碎碎念:已知是需要去重,因为选两个相同的数,产生的还是那个数。好像还和等差数列有关。 
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=2e5 +5 ;ll gcd (ll a,ll b)  while (a&&b)if (a>b)a%=b;else  b%=a;return  a+b;int  main () int  t;scanf ("%d" ,&t);while (t--)0 },i,j;scanf ("%lld%lld" ,&n,&k);for (i=1 ;i<=n;i++)scanf ("%lld" ,&a[i]);sort (a+1 ,a+1 +n);0 ;for (i=2 ;i<=n;i++)gcd (g,a[i]-a[i-1 ]);if (g&&(a[1 ]-k)%g==0 ||a[1 ]==k)printf ("YES\n" );else  printf ("NO\n" );return  0 ;
注:标程存在的bug已通过特判修复:如果元素值均相同,g将为0,无法进行求余运算,此时若题给元素值不等于目标值,则NO,等于则YES。
快速幂取模+找规律
我是通过打表发现,对于每个基 a ,在 k 增长时,结果有一定的周期性。
先存下 k 取较小值(1,2,3…)时的的结果,每算出一个新值,便与前面的所有值比对,如果有相同的值,便可以找到循环节和循环起点,再计算 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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;long  long  qs (long  long  a,long  long  b,long  long  p) long  long  ans=1 %p;while (b)if (b&1 )ans=ans*a%p;1 ;return   ans;int  main () 20 ]={0 },mbc,xhj=0 ;1 ]=a;1 ;for (i=2 ;i<20 &&!xhj;i++,mbc++)1 ]=qs (li[mbc],li[mbc],1000 );for (j=1 ;j<=mbc;j++)if (li[j]==li[mbc+1 ])1 -j;if (k>mbc-xhj)printf ("%lld" ,li[mbc-xhj+k]);}else  printf ("%lld" ,li[k]);return  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 33 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;int  main () int  a[100005 ],n,i,j,b,l[100005 ];for (i=1 ;i<=n;i++)scanf ("%d" ,&a[i]);1 ;1 ;for (i=1 ;i<=n;i++)while (tim>m)for (i=b;i<=n;i++)1 ;for (i=1 ;i<=n;i++)if (i!=1 )printf (" " );printf ("%d" ,l[i]);return  0 ;
字符串处理
分别计数aceptd六个字母的出现次数,统计每个字母能组成单词份数的最小值即可(份数即出现次数 / 在单个单词中的个数)。
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;typedef  long  long  ll;int  main () char  g[50005 ];while (cin>>g)int  i,a=0 ,c=0 ,e=0 ,p=0 ,t=0 ,d=0 ;for (i=0 ;g[i];i++)if (g[i]=='a' )a++;else  if (g[i]=='c' )c++;else  if (g[i]=='e' )e++;else  if (g[i]=='p' )p++;else  if (g[i]=='t' )t++;else  if (g[i]=='d' )d++;int  ans=min (e/2 ,c/2 );min (ans,a);min (ans,p);min (ans,t);min (ans,d);printf ("%d\n" ,ans);return  0 ;
贪心
这道题特别像这个 。
我们可以把排序问题拆分成从输入顺序开始的足够多次对换,只要我们找到能更趋近与所求结果的对换条件,我们便可以依照此条件直接排序。
假设现在有两道题,i 与 i + 1,我们要找到一种使对换后做两题时耗费的精力值更小 的条件。
对换前,消耗精力值之和为( b 1 + b 2 + . . . + b i − 1 ) ∗ a i + ( b 1 + b 2 + . . . + b i − 1 ) ∗ a i + 1 + b i ∗ a i + 1 (b_1+b_2+...+b_{i-1})*a_i+(b_1+b_2+...+b_{i-1})*a_{i+1}+b_i*a_{i+1} ( b 1  + b 2  + . . . + b i − 1  ) ∗ a i  + ( b 1  + b 2  + . . . + b i − 1  ) ∗ a i + 1  + b i  ∗ a i + 1  
对换后,消耗精力值之和为( b 1 + b 2 + . . . + b i − 1 ) ∗ a i + b i + 1 ∗ a i + ( b 1 + b 2 + . . . + b i − 1 ) ∗ a i + 1 (b_1+b_2+...+b_{i-1})*a_i+b_{i+1}*a_i+(b_1+b_2+...+b_{i-1})*a_{i+1} ( b 1  + b 2  + . . . + b i − 1  ) ∗ a i  + b i + 1  ∗ a i  + ( b 1  + b 2  + . . . + b i − 1  ) ∗ a i + 1  
减掉相同部分后,若满足对换后小于对换前,则有b i + 1 ∗ a i < b i ∗ a i + 1 b_{i+1}*a_i<b_i*a_{i+1} b i + 1  ∗ a i  < b i  ∗ a i + 1  
这道题的条件便是 bi+1  / ai+1  < bi  / ai 
通过结构体+cmp实现。
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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;struct  pro int  a,b;500005 ];bool  cmp (pro x,pro y) return  (double )x.b/x.a<(double )y.b/y.a;int  main () int  n,i;for (i=1 ;i<=n;i++)scanf ("%d%d" ,&p[i].a,&p[i].b);sort (p+1 ,p+n+1 ,cmp);0 ,ans=0 ;for (i=1 ;i<=n;i++)printf ("%lld" ,ans);return  0 ;
中位数
即找到一点,距离所有点的距离之和最短。
和 货仓选址  基本相同
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;typedef  long  long  ll;int  main () int  n,i,a[100005 ];for (i=1 ;i<=n;i++)scanf ("%d" ,&a[i]);sort (a+1 ,a+n+1 );0 ;for (i=1 ;i<=n;i++)abs (a[i]-a[n+1 >>1 ]);printf ("%lld" ,ans);return  0 ;
在游戏规则限制内,从顺时针或逆时针方向看,三个牌的顺序是无法被改变的。
如样例来说,从顺时针方向读,三个牌的顺序永远是 ABCABCA…,如果目标顺序相同,则可解,如目标顺序不相同,如 ACBABCA… ,则不可解。
接收之后比对顺序即可。
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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;int  main () int  a[6 ]={0 },b[6 ]={0 },ac=0 ,bc=0 ,f=-1 ,i,j;char  s[5 ];for (i=0 ;i<=1 ;i++)if (s[i]=='A' )a[ac++]=1 ;else  if (s[i]=='B' )a[ac++]=2 ;else  if (s[i]=='C' )a[ac++]=3 ;for (i=1 ;i>=0 ;i--)if (s[i]=='A' )a[ac++]=1 ;else  if (s[i]=='B' )a[ac++]=2 ;else  if (s[i]=='C' )a[ac++]=3 ;for (i=0 ;i<=1 ;i++)if (s[i]=='A' )b[bc++]=1 ;else  if (s[i]=='B' )b[bc++]=2 ;else  if (s[i]=='C' )b[bc++]=3 ;for (i=1 ;i>=0 ;i--)if (s[i]=='A' )b[bc++]=1 ;else  if (s[i]=='B' )b[bc++]=2 ;else  if (s[i]=='C' )b[bc++]=3 ;for (i=3 ;i<=5 ;i++)b[i]=b[i-3 ];for (i=0 ;i<3 ;i++)if (b[i]==a[0 ])for (j=1 ;j<=2 ;j++)if (b[i+j]!=a[j])f=0 ;if (f==-1 )f=1 ;if (f==1 )printf ("YES" );else  printf ("NO" );return  0 ;
DP
对于每一个 b ,能和前面的每一个 a 组成一个 ab 串;
更新记录目前 a,ab,abc 的个数即可
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;typedef  long  long  ll;int  main () char  a[1000006 ];0 ,on=0 ,tw=0 ,tr=0 ;for (i=0 ;a[i];i++)if (a[i]=='a' )on++;else  if (a[i]=='b' )tw+=on;else  if (a[i]=='c' )tr+=tw;printf ("%lld" ,tr);return  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 #include  <bits/stdc++.h>  using  namespace  std;typedef  long  long  ll;int  main () int  n,a[102 ],i,mark=0 ,sum=0 ;for (i=1 ;i<=n;i++)scanf ("%d" ,&a[i]);if (a[i]%10 !=0 )if (!mark)mark=a[i];else  mark=min (mark,a[i]);if (sum%10 !=0 )printf ("%d" ,sum);else if (mark)printf ("%d" ,sum-mark);else  printf ("0" );return  0 ;
特别感谢老师的proA标程!!!