思路  求P + Q ,   P + R ,   Q + R P+Q,~P+R,~Q+R P + Q ,   P + R ,   Q + R 
代码 
1 2 3 4 5 6 void  eachT ()      int  a[3 ];     scanf ("%d %d %d" , &a[0 ], &a[1 ], &a[2 ]);     std::sort (a, a + 3 );     printf ("%d\n" , a[0 ] + a[1 ]); } 
思路  如果前 / 后两个数在1 ∼ 12 1\sim12 1 ∼ 1 2 
代码 
1 2 3 4 5 6 7 8 9 void  eachT ()      int  n;     scanf ("%d" , &n);     int  a = n / 100 , b = n % 100 ;      if  ((a >= 1  && a <= 12 ) && (b >= 1  && b <= 12 )) printf ("AMBIGUOUS" );     if  ((a >= 1  && a <= 12 ) && (b < 1  || b > 12 )) printf ("MMYY" );     if  ((a < 1  || a > 12 ) && (b >= 1  && b <= 12 )) printf ("YYMM" );     if  ((a < 1  || a > 12 ) && (b < 1  || b > 12 )) printf ("NA" ); } 
注意  || 的优先级高于 &&,要加括号.
思路  只要0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 
代码 
1 2 3 4 5 6 7 8 9 10 void  eachT ()      scanf ("%s" , s);     int  len = strlen (s);     int  cnt0 = 0 , cnt1 = 0 ;     for  (int  i = 0 ; i < len; ++i) {         if  (s[i] == '0' ) ++cnt0;         else  ++cnt1;     }     printf ("%d\n" , 2  * min (cnt0, cnt1)); } 
「d d l ddl d d l  
思路  想想上学期的 ddl 是如何安排时间的……一定是卡着 ddl 完成,然后从 ddl 往前推开始完成的时间.我们按照 ddl 按时间倒序,倒着推导每一项任务的开始完成时间,这个时间便是下一项任务的 ddl.
代码 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct  node  {    ll len, ddl; } b[maxN]; bool  cmp (node a, node b)  return  a.ddl > b.ddl; }void  eachT ()      int  n;     scanf ("%d" , &n);     for  (int  i = 1 ; i <= n; ++i) scanf ("%d %d" , &b[i].len, &b[i].ddl);     std::sort (b + 1 , b + n + 1 , cmp);      ll ddl = b[1 ].ddl; bool  flag = 1 ;     for  (int  i = 1 ; i <= n; ++i) {         ddl = min (b[i].ddl, ddl);         if  (ddl < b[i].len) flag = 0 ;          ddl -= b[i].len;      }     printf ("%s\n" , flag ? "Yes"  : "No" ); } 
注意  别直接 copy 样例就输出了,XX 是需要计算的( 你猜为什么 WA:AC=1:1 
思路  假定不能百度搜索在线日期计算器,那就只能手算了:
大致推断是在1024 1024 1 0 2 4 2022.2.11 ∼ 3046.2.10 2022.2.11\sim3046.2.10 2 0 2 2 . 2 . 1 1 ∼ 3 0 4 6 . 2 . 1 0 
从2022 ∼ 3046 2022\sim3046 2 0 2 2 ∼ 3 0 4 6 4 4 4 1024 4 = 256 \frac{1024}{4}=256 4 1 0 2 4  = 2 5 6 100 100 1 0 0 2100 ,   2200 ,   … ,   3000 2100,~2200,~\dots,~3000 2 1 0 0 ,   2 2 0 0 ,   … ,   3 0 0 0 10 10 1 0 400 400 4 0 0 2 2 2 256 − 10 + 2 = 248 256-10+2=248 2 5 6 − 1 0 + 2 = 2 4 8 
于是从2022.2.11 ∼ 3046.2.10 2022.2.11\sim3046.2.10 2 0 2 2 . 2 . 1 1 ∼ 3 0 4 6 . 2 . 1 0 1024 × 365 + 248 1024\times365+248 1 0 2 4 × 3 6 5 + 2 4 8 3046.2.10 3046.2.10 3 0 4 6 . 2 . 1 0 248 248 2 4 8 3046.1.1 ∼ 3046.2.10 3046.1.1\sim3046.2.10 3 0 4 6 . 1 . 1 ∼ 3 0 4 6 . 2 . 1 0 31 + 10 = 41 31+10=41 3 1 + 1 0 = 4 1 248 − 41 = 202 = 31 + 30 + 31 + 30 + 31 + 31 + 13 248-41=202=31+30+31+30+31+31+13 2 4 8 − 4 1 = 2 0 2 = 3 1 + 3 0 + 3 1 + 3 0 + 3 1 + 3 1 + 1 3 3045 3045 3 0 4 5 6 6 6 13 13 1 3 30 − 13 + 1 = 18 30-13+1=18 3 0 − 1 3 + 1 = 1 8 
代码 
1 2 3 void  eachT ()      printf (" 新年快乐%(^_^)% from 3045-06-08" ); } 
提示  本题是全角 %,直接 copy 就可以输出,如果要求输出英文半角 %,需改为 printf(" 新年快乐 %%(^_^)%% from 3045-06-08").
思路  电脑模拟操作,我们总是操作最大数和最小数:
1 2 3 4 5 6 7 8 9 10 11 12 const  int  maxN = 1e3 ; void  eachT ()      int  a[3 ];     scanf ("%d %d %d" , &a[0 ], &a[1 ], &a[2 ]);     bool  flag = 0 ;     for  (ll i = 0 ; i < maxN; ++i) {         std::sort (a, a + 3 );         if  (a[0 ] == a[2 ]) { flag = 1 ; break ; }          a[2 ] -= a[0 ], a[0 ] *= 2 ;      }     printf ("%s\n" , flag ? "together"  : "no way" ); } 
我试图推导出Θ ( 1 ) \Theta(1) Θ ( 1 ) 
设所给的数是a , b , c a,b,c a , b , c 1 1 1 3 ∤ a + b + c 3\nmid a+b+c 3 ∤ a + b + c 
因为用电脑计算出的结果是这样的:
1 2 3 4 5 1  1  7    1  2  6    1  3  5    1  4  4    1  5  9    1  6  8    1  7  7    1  8  9 2  2  5    2  3  4    2  4  9    2  5  8    2  6  7    2  7  9    3  4  8    3  5  7 3  7  8    4  4  7    4  5  6    4  5  9    4  7  7    4  8  9    5  5  8    5  6  7 5  7  9    5  8  8    6  7  8 
更大的数也是毫无规律:
1 2 3 4 5 6 7 8 9 10 1  1  7    1  1  13   1  1  16   1  1  19   1  1  25   1  1  28   1  1  31   1  1  34 1  1  37   1  1  40   1  1  43   1  1  49   1  1  52   1  1  55   1  1  58   1  1  61 1  1  64   1  1  67   1  1  70   1  1  73   1  1  76   1  1  79   1  1  82   1  1  85 1  1  88   1  1  91   1  1  97   1  1  100  1  1  103  1  1  106  1  1  109  1  1  112 1  1  115  1  1  118  1  1  121  1  1  124  1  1  127  1  1  130  1  1  133  1  1  136 1  1  139  1  1  142  1  1  145  1  1  148  1  1  151  1  1  154  1  1  157  1  1  160 1  1  163  1  1  166  1  1  169  1  1  172  1  1  175  1  1  178  1  1  181  1  1  184 1  1  187  1  1  193  1  1  196  1  1  199  1  1  202  1  1  205  1  1  208  1  1  211 1  1  214  1  1  217  1  1  220  1  1  223  1  1  226  1  1  229  1  1  232  1  1  235 1  1  238  1  1  241  1  1  244  1  1  247  1  1  250  1  1  253  1  1  256  1  1  259 
思路  假设你自己是个 贪心的大吃货 ,你每到一个景点就会吃,如果没得吃怎么办?拿食材呗.去哪里拿?贪心的你当然是选择这个景点之前的可以拿最多食材的那个地方拿.模拟这个过程即可.
注意 
你实在是太饿了,在一个地方拿还不够吃,可能要反复寻找食材,所以是 while 而非 if; 你如果全程一直有的吃,也是要拿食材的,别忘了你是个贪心的人,吃不下也要拿; 别太贪心,一个景点只能拿一次,所以领取之后要把这个地方的食材清空. (以上三条是帮同学 debug 时发现的问题 显然这道题如果不贪心不贪吃是做不出来的 ) 
代码 
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 int  a[maxN];int  ans, cnt;void  greed (int  x)      int  maxn = 0 ;      for  (int  i = 0 ; i < x; ++i)         if  (a[maxn] < a[i]) maxn = i;         ++cnt;                                      ans += a[maxn];                          a[maxn] = 0 ;                          } void  eachT ()      int  n, x;     scanf ("%d" , &n);     for  (int  i = 0 ; i < n; i++) scanf ("%d" , &a[i]);     for  (int  i = 1 ; i < n; i++) {         scanf ("%d" , &x);         ans -= x;          while  (ans < 0  && cnt <= 3 ) greed (i);      }     while  (cnt < 3 ) greed (n);                      printf ("%d\n" , cnt <= 3  ? ans : -1 );      } 
思路  区间 DP.
注意到,出现的回文串一定由是a a a b b b a 和 aaaabcaa,可以是 a 和前面的 aaaa 组合,可以是 a 和后面的 aa 组合,但不能是 a 和 aaaaaa 组合),所以我们可以 DP 哪些区间组成的回文串最长.
状态:dp[l1][r1][l2][r2] 表示a a a [ l 1 , r 1 ] [l_1,r_1] [ l 1  , r 1  ] b b b [ l 2 , r 2 ] [l_2,r_2] [ l 2  , r 2  ] 是否  可以组成回文串;
始态:a a a 0 0 0 b b b 0 0 0 dp 全部赋值为 1;
末态:所有满足 dp[l1][r1][l2][r2]=1 的 len1+len2 最大值;
状转方程:dp[l1][r1][l2][r2]=a[l1] == a[l1] == a[r1] && dp[l1+1][r1-1][l2][r2] || b[l2] == b[r2] && dp[l1][r1][l2+1][r2-1] || a[l1] == b[r2] && dp[l1+1][r1][l2][r2-1] || b[l2] == a[r1] && dp[l1][r1-1][l2+1][r2]
状转方程的解释
满足以下四种情形之一的,dp=1:
a a a l 1 l_1 l 1  a a a l 2 l_2 l 2  a a a [ l 1 + 1 , r 1 − 1 ] [l_1+1,r_1-1] [ l 1  + 1 , r 1  − 1 ] b b b [ l 2 , r 2 ] [l_2,r_2] [ l 2  , r 2  ] dp[l1+1][r1-1][l2][r2]=1,那么a a a [ l 1 , r 1 ] [l_1,r_1] [ l 1  , r 1  ] b b b [ l 2 , r 2 ] [l_2,r_2] [ l 2  , r 2  ] a[l1] == a[r1] && dp[l1+1][r1-1][l2][r2];
a a a l 1 l_1 l 1  b b b r 2 r_2 r 2  a a a [ l 1 + 1 , r 1 ] [l_1+1,r_1] [ l 1  + 1 , r 1  ] b b b [ l 2 , r 2 − 1 ] [l_2,r_2-1] [ l 2  , r 2  − 1 ] 
b b b b b b 
b b b a a a 
(如果a a a b b b 
把上面四种情形放在一个大大的 if 里面,然后更新最大值就好咯.
代码 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void  eachT ()      memset (dp, 0 , sizeof  dp);      std::cin >> (a+1 ) >> (b+1 );     int  ans = 1 , lena = strlen (a+1 ), lenb = strlen (b+1 );     for  (int  len1 = 0 ; len1 <= lena; ++len1)     for  (int  len2 = 0 ; len2 <= lenb; ++len2)     for  (int  l1 = 1 , r1 = len1; r1 <= lena; ++l1, ++r1)     for  (int  l2 = 1 , r2 = len2; r2 <= lenb; ++l2, ++r2) {         if  (len1 + len2 <= 1 ) dp[l1][r1][l2][r2] = 1 ;          else  if  (a[l1] == a[r1] && dp[l1+1 ][r1-1 ][l2][r2]               || b[l2] == b[r2] && dp[l1][r1][l2+1 ][r2-1 ]               || a[l1] == b[r2] && dp[l1+1 ][r1][l2][r2-1 ]               || b[l2] == a[r1] && dp[l1][r1-1 ][l2+1 ][r2]) {             dp[l1][r1][l2][r2] = 1 ;             ans = max (ans, len1 + len2);          }     }     printf ("%d\n" , ans); } 
思路  熟知
勒讓德定理 :在n ! n! n ! p p p v p ( n ! ) = ∑ k = 1 p k ≤ n ⌊ n p k ⌋ = n − S p ( n ) p − 1 . v_p(n!)=\displaystyle\sum\limits_{k=1}^{p^k\le n}\bigg\lfloor\dfrac{n}{p^k}\bigg \rfloor=\dfrac{n-S_p(n)}{p-1}. v p  ( n ! ) = k = 1 ∑ p k ≤ n  ⌊ p k n  ⌋ = p − 1 n − S p  ( n )  . S p ( n ) S_p(n) S p  ( n ) n n n p p p 
\begin{cases}
1, & \text {if} n=1 \
\displaystyle S_p\Big(\frac{n}{p}\Big), & \text {if} p\mid n \
S_p(n-1)+1, & \text {otherwise}.
\end{cases}
我们使用它第一个形式,循环求和.
代码 
1 2 3 4 5 6 7 8 9 10 11 void  eachT ()      ll n;     scanf ("%lld" , &n);     for  (ll p = 2 ; p <= n; ++p) {         if  (!isntPrime[p]) {             ll sum = 0 ;             for  (ll k = p; k <= n; k *= p) sum += n / k;              if  (sum) printf ("%lld %lld\n" , p, sum);          }      } } 
注意  全力开 long long,可以测试一下输入 1000000 能不能出结果,如果什么都输不出来很有可能是 long long 的问题.
思路  想要间距尽可能小,一定是左边的向右跳,右边的向左跳,但是界限不确定,我们可以枚举界限,一一计算.假设现在的分界点是i i i a 1 + x ∼ a i − 1 + x a_1+x\sim a_{i-1}+x a 1  + x ∼ a i − 1  + x a i − x ∼ a n − x a_i-x\sim a_n-x a i  − x ∼ a n  − x min  ( a 1 + x ,   a i − x ) ∼ max  ( a i − 1 + x ,   a n − x ) \min(a_1+x,~a_i-x)\sim \max(a_{i-1}+x,~a_n-x) min ( a 1  + x ,   a i  − x ) ∼ max ( a i − 1  + x ,   a n  − x ) 
代码 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void  eachT ()      int  n, x;     scanf ("%d" , &n);     for  (int  i = 1 ; i <= n; ++i) scanf ("%d" , &a[i]);     std::sort (a + 1 , a + n + 1 );      scanf ("%d" , &x);          int  ans = 1e18 ;     for  (int  i = 2 ; i <= n; ++i) {         ans = min (max (a[n]-x, a[i-1 ]+x) - min (a[i]-x, a[1 ]+x), ans);     }     ans = min (a[n] - a[1 ], ans);      printf ("%d\n" , ans); } 
思路  哈希.参见Link 
倒着按照长度循环,判断前缀和后缀是否相同,如果相同,再寻找中间是否有相同的,如果找到就终止循环.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const  int  H = 131 ;void  init ()  0 ] = 1 ; for  (int  i = 1 ; i < maxN; ++i) P[i] = P[i - 1 ] * H; }ull get (int  l, int  r)  return  sum[r] - sum[l - 1] * P[r - l + 1] ;void  eachT ()      init ();     std::cin >> s; int  m = s.size (); s = " "  + s;     for  (int  i = 1 ; i < m; ++i) {         sum[i] = sum[i - 1 ] * H + s[i] - 'a' ;     }         for  (int  len = m - 1 ; len >= 1 ; --len) {         ull h1 = get (1 , len), h2 = get (m - len + 1 , m);         if  (h1 != h2) continue ;         for  (int  i = 2 ; i <= m - len; ++i) {             h2 = get (i, i + len - 1 );             if  (h1 == h2) {                 for  (int  j = 1 ; j <= len; ++j)                     std::cout << s[j];                 return ;             }         }     }     std::cout << "I'll write one for you" ; } 
(涉及知识盲区了)(暂无代码,不确定这个思路能否实现)
思路 
(此方法复杂度极高,不建议学习)
思路 
思路  和 K 题类似的哈希.因为和A A A s 0 s_0 s 0  s 0 s_0 s 0  2 l e n 0 2len_0 2 l e n 0  map 标记.对于每个测试样例,从头到尾遍历它的哈希值,并判断这个哈希值是否出现过.
代码 
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 const  int  H = 131 ;std::map<int , int > mp; void  init ()  0 ] = 1 ; for  (int  i = 1 ; i < maxN; ++i) P[i] = P[i - 1 ] * H; }ull get0 (int  l, int  r)   { return  sum0[r] - sum0[l - 1 ] * P[r - l + 1 ]; }ull get (int  l, int  r)   { return  sum[r] - sum[l - 1 ] * P[r - l + 1 ]; }void  eachT ()      init ();      std::cin >> s0; int  len0 = s0. size (); s0 = " "  + s0;      for  (int  i = 1 ; i <= len0; ++i) sum0[i] = sum0[i - 1 ] * H + s0[i];      mp[get0 (1 , len0)] = 1 ;      for  (int  i = len0 + 1 ; i <= 2  * len0; ++i) {         sum0[i] = sum0[i - 1 ] * H + s0[i - len0];         mp[get0 (i - len0 + 1 , i)] = 1 ;      }     int  T; std::cin >> T; while  (T--) {          std::cin >> s; int  len = s.size (); s = " "  + s;         for  (int  i = 1 ; i <= len; ++i) sum[i] = sum[i - 1 ] * H + s[i];         int  ans = 0 ;         for  (int  l = 1 , r = len0; r <= len; ++l, ++r) {             if  (mp[get (l, r)]) ++ans;         }          std::cout << ans << '\n' ;     } }