A - qh与复读机I 
A、每次按顺序给出$ n $个字符串,求出每个字符串是前面多少个字符串的前缀和后缀
 
tire树
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 #define  maxn 1000007 struct  Node {	int  child[26 ]; 	int  sum; 	void  init ()  		for (int  i = 0 ;i < 26 ;i++) child[i] = 0 ; 		sum = 0 ; 	} }Tree[2 ][maxn]; int  cnt1 = 0 ,cnt2 = 0 ;int  insert (bool  statu,const  string& s) 	int  len = s.length (); 	int  now = 0 ; 	for (int  i = 0 ;i < len;i++){ 		int  pos = s[i] - 'a' ; 		if (Tree[statu][now].child[pos] == 0 ){ 			int  nxt = (statu ? ++cnt2 : ++cnt1); 			Tree[statu][now].child[pos] = nxt; 			Tree[statu][nxt].init (); 		} 		now = Tree[statu][now].child[pos]; 		Tree[statu][now].sum ++; 	} 	return  Tree[statu][now].sum - 1 ; } int  main () 	int  n; 	string s; 	cin>>n; 	for (int  i = 1 ;i <= n;i++){ 		cin>>s; 		cout<<insert (0 ,s)<<" " ; 		reverse (s.begin (),s.end ()); 		cout<<insert (1 ,s)<<endl; 	} 	return  0 ; } 
B - qh与复读机II 
B、给定一个字符串$ S $,求出这个字符串的所有循环节大小
 
KMP fail数组
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 char  s[1000007 ]; int  nxt[1000007 ];vector<int > ans; void  KMP (char  *s)     nxt[0 ] = 0 ;     nxt[1 ] = 0 ;     int  j;     int  len = strlen (s);     for (int  i = 1 ;i<len;i++){         j = nxt[i];         while (s[i]!=s[j]&&j) j = nxt[j];         nxt[i+1 ] = s[i]==s[j]?j+1 :0 ;      } } int  main ()     cin>>s;     KMP (s);     int  len = strlen (s);     int  x = nxt[len];     while (x){         ans.push_back (len - x);         x = nxt[x];     }     ans.push_back (len);     for (int  i = 0 ;i < ans.size ();i++) cout<<ans[i]<<" " ;     cout<<endl;     return  0 ; } 
C - qh与复读机III 
C、给出字符串$ S $和$ T $,求出$ T $在$ S $中出现的每一个位置
 
KMP
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 char  s1[1000007 ],s2[1000007 ]; int  nxt[1000007 ];void  KMP (char  *s)     nxt[0 ] = 0 ;     nxt[1 ] = 0 ;     int  j;     int  len = strlen (s);     for (int  i = 1 ;i<len;i++)     {         j = nxt[i];         while (s[i]!=s[j]&&j) j = nxt[j];         nxt[i+1 ] = s[i]==s[j]?j+1 :0 ;      } } void  solve ()     int  n = strlen (s1),m = strlen (s2);     int  j=0 ;     for (int  i = 0 ;i<n;i++)     {          while (s1[i]!=s2[j]&&j) j = nxt[j];         if (s1[i]==s2[j]) j++;         if (j==m){cout<<i-j+2 <<" " ;}     } } int  main ()     cin>>s1>>s2;     KMP (s2);     solve ();     return  0 ; } 
D - qh与复读机IV 
D、给出一堆模式串$T_i$,求出每个模式串在待匹配串里面的出现次数
 
AC自动机
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 93 94 95 96 97 98 int  n;char  s1[1000007 ],s2[1000007 ];int  ans[100007 ];int  tid[100007 ];struct  acnode {    acnode *child[26 ];     int  id;     acnode *fail; }; void  init (acnode *root)     for (int  i = 0 ;i<26 ;i++) root->child[i] = NULL ;     root->id = 0 ;     root->fail = NULL ; } void  insert (acnode *root,char  *s,int  id)     int  len = strlen (s);     acnode *t = root;     for (int  i = 0 ;i<len;i++){         int  pos = s[i] - 'a' ;         if (t->child[pos] == NULL ){             acnode *newnode = new  acnode;             init (newnode);             t->child[pos] = newnode;         }         t = t->child[pos];     }     if (t -> id != 0 ) tid[id] = t -> id;     else  t -> id = id,tid[id] = t -> id; } void  getfail (acnode *root)     queue<acnode*> q;     q.push (root);     while (!q.empty ()){         acnode *now = q.front ();         q.pop ();         for (int  i = 0 ;i<26 ;i++){             if (now->child[i] != NULL ){                 acnode *p;                 if (now == root){                     now->child[i]->fail = root;                 }                 else {                     p = now->fail;                     while (p != NULL ){                         if (p->child[i] != NULL ){                             now->child[i]->fail = p->child[i];                             break ;                         }                         p = p->fail;                     }                     if (p == NULL ) now->child[i]->fail = root;                 }                 q.push (now->child[i]);             }         }     } } void  query (acnode *root,char  *s)     acnode *p = root;     int  len = strlen (s);     for (int  i = 0 ;i<len;i++){         int  pos = s[i] - 'a' ;         while (p->child[pos] == NULL  && p!= root) p = p->fail;         p = p->child[pos];         if (!p) p = root;         acnode *now = p;         while (now != root){             if (now->id > 0 )                 ans[now->id] ++;             now = now->fail;         }     } } acnode *root; int  main () 	cin>>s2;     cin>>n;     root = new  acnode;     init (root);     for (int  i = 1 ;i<=n;i++){         cin>>s1;         insert (root,s1,i);     }     getfail (root);     query (root,s2);     for (int  i = 1 ;i <= n;i++){     	cout<<ans[tid[i]]<<endl;     }     return  0 ; } 
E - qh与复读机V 
E、和上一个题一样,但是有数据加强
 
AC自动机 last优化
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 int  n,cnt = 0 ;char  s1[1000007 ],s2[1000007 ];int  ans[100007 ];int  tid[100007 ];int  last[1000007 ];struct  acnode {    int  child[26 ];     int  id;     int  fail;          void  init ()          for (int  i = 0 ;i < 26 ;i++) child[i] = 0 ;         fail = 0 ;         id = 0 ;     } }Node[1000007 ]; void  insert (char  *s,int  id)     int  len = strlen (s);     int  now = 0 ;     for (int  i = 0 ;i < len;i++){         if (Node[now].child[s[i] - 'a' ] == 0 ){             Node[now].child[s[i] - 'a' ] = ++cnt;             Node[cnt].init ();         }         now = Node[now].child[s[i] - 'a' ];     }     if (Node[now].id == 0 ) Node[now].id = id,tid[id] = id;     else  tid[id] = Node[now].id; } void  getfail ()     queue<int > q;     for (int  i = 0 ;i < 26 ;i++){         if (Node[0 ].child[i] != 0 ){             Node[Node[0 ].child[i]].fail = 0 ;             q.push (Node[0 ].child[i]);         }     }     while (!q.empty ()){         int  now = q.front ();         q.pop ();         for (int  i = 0 ;i < 26 ;i++){             if (Node[now].child[i] != 0 ){                 int  nxt = Node[now].child[i];                 Node[Node[now].child[i]].fail = Node[Node[now].fail].child[i];                 q.push (Node[now].child[i]);                 last[nxt] = Node[Node[nxt].fail].id ? Node[nxt].fail : last[Node[nxt].fail];              }             else  Node[now].child[i] = Node[Node[now].fail].child[i];         }     } } void  query (char  *s)     int  len = strlen (s);     int  now = 0 ;     for (int  i = 0 ;i < len;i++){         now = Node[now].child[s[i] - 'a' ];         for (int  t = now;t;t = last[t]){             if (Node[t].id > 0 ){                 ans[Node[t].id] ++;             }         }     } } int  main ()     cin>>s2;     cin>>n;     for (int  i = 1 ;i<=n;i++){         cin>>s1;         insert (s1,i);     }     getfail ();     query (s2);     for (int  i = 1 ;i <= n;i++){         cout<<ans[tid[i]]<<endl;     }     return  0 ; } 
F - qh与复读机VI 
F、给定一个字符串$S$,以及一个字符串$T$,要求求出所有的$S$的子串与$T$的一个前缀拼起来是回文串的情况的总数,而且要求子串长度大于前缀
 
exkmp manacher
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 string s,t; ll nxt[1000007 ],exnxt[1000007 ]; char  s2[2000007 ];ll p[2000007 ],id = 1 ,mx = 1 ,ans = -1 ; ll pre[2000007 ]; void  KMP () 	ll len = t.length (),pos,i = 0 ,j;     nxt[0 ] = len;     while (t[i] == t[i + 1 ] && i + 1  < len) i++;     nxt[1 ] = i;     pos = 1 ;     for (i = 2 ;i < len;i++){     	if (nxt[i - pos] + i < nxt[pos] + pos) nxt[i] = nxt[i - pos];     	else {     		j = nxt[pos] + pos - i;     		if (j < 0 ) j = 0 ;     		while (i + j < len && t[i + j] == t[j]) j++;     		nxt[i] = j;     		pos = i;     	}     } } void  exkmp () 	ll i = 0 ,j,pos = 0 ,len1 = s.length (),len2 = t.length (); 	while (s[i] == t[i] && i < len1 && i < len2) i++; 	exnxt[0 ] = i; 	for (i = 1 ;i < len1;i++){ 		if (nxt[i - pos] + i < exnxt[pos] + pos) exnxt[i] = nxt[i - pos]; 		else { 			j = exnxt[pos] + pos - i; 			if (j < 0 ) j = 0 ; 			while (i + j < len1 && j < len2 && s[j + i] == t[j]) j++; 			exnxt[i] = j; 			pos = i; 		} 	} } ll init ()  {    s2[0 ] = '$' ;     s2[1 ] = '#' ;     ll j = 2 ;     ll len = s.length ();     for (ll i = 0 ;i<len;i++){         s2[j++] = s[i];         s2[j++] = '#' ;     }     s2[j] = '\0' ;     return  j; } void  manacher () 	ll len = init (); 	for (ll i = 1 ;i<len;i++){         if (i < mx) p[i] = min (p[2  * id - i],mx - i);         else  p[i] = 1 ;         while (s2[i - p[i]] == s2[i + p[i]]) p[i] ++;         if (mx < i + p[i]){             id = i;             mx = i + p[i];         }     } } int  main () 	cin>>s>>t; 	manacher (); 	ll len = s.length (); 	for (ll i = len * 2 ;i >= 2 ;i--){ 		ll x = i / 2 ; 		pre[x]++; 		pre[x - (p[i] / 2 )] --; 	} 	for (ll i = len;i >= 1 ;i--) pre[i] += pre[i + 1 ]; 	reverse (s.begin (),s.end ()); 	KMP (); 	exkmp (); 	ll ans = 0 ; 	for (ll i = 1 ;i <= len;i++){ 		ans += exnxt[len - i + 1 ] * pre[i] * 1LL ; 	} 	cout<<ans<<endl;     return  0 ; } 
G - qh与复读机VII 
G、给出一个数字串已经一个模数,求出对应数字串的每个不同回文数相加的和在取模后的值的大小
 
快速幂 回文自动机
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 struct  Node {    int  child[10 ];     int  fail,len;     ll value;     void  init ()          mst (child,0 );         fail = len = 0 ;         value = 0 ;     } }node[maxn]; char  s[maxn];int  last,tot = 0 ;ll ans = 0 ,xyy; ll QuickMod (ll a,ll b)  {    ll res = 1 ,t = a;     while (b){         if (b&1 ) res = (res * t) % xyy;         t = (t * t) % xyy;         b >>= 1 ;     }     return  res; } void  insert (int  c,int  x)     int  p = last;     while (s[x - node[p].len - 1 ] != s[x]) p = node[p].fail;     if (!node[p].child[c]){         int  v = ++tot,k = node[p].fail;         node[v].len = node[p].len + 2 ;         while (s[x - node[k].len - 1 ] != s[x]) k = node[k].fail;         node[v].fail = node[k].child[c];         node[p].child[c] = v;         if (p == 1 ){             node[v].value = c;             ans = (ans + c) % xyy;         }         else {             ll value = (node[p].value * 10  % xyy + c * QuickMod (10 ,node[v].len - 1  % xyy) + c) % xyy;             ans = (ans + value) % xyy;             node[v].value = value;         }     }     last = node[p].child[c]; } void  init ()     node[0 ].init ();     node[1 ].init ();     node[0 ].fail = 1 ;     node[1 ].len = -1 ;     tot = 1 ;     last = 0 ;     s[0 ] = -1 ; } int  main ()     init ();     cin>>s + 1 >>xyy;     int  len = strlen (s + 1 );     for (int  i = 1 ;s[i];i++){         insert (s[i] - '0' ,i);     }     cout<<ans<<endl;     return  0 ; } 
H - qh与复读机VIII 
H、给出一堆模式串以及对应的权重,要求组出一个字符串让其权重和最大,对应某一个模式串出现一次算一次这个模式串的权重,字符串长度限制为$L$
 
AC自动机 trie图
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 struct  acnode {    int  child[26 ];     ll val;     int  fail;          void  init ()          for (int  i = 0 ;i < 26 ;i++) child[i] = 0 ;         fail = 0 ;         val = 0 ;     } }Node[1000007 ]; ll cnt; ll n,l,w; char  s[600 ];ll f[2007 ][600 ]; void  getfail ()     queue<int > q;     for (int  i = 0 ;i < 26 ;i++){         if (Node[0 ].child[i] != 0 ){             Node[Node[0 ].child[i]].fail = 0 ;             q.push (Node[0 ].child[i]);         }     }     while (!q.empty ()){         int  now = q.front ();         q.pop ();         if (Node[Node[now].fail].val) Node[now].val += Node[Node[now].fail].val;         for (int  i = 0 ;i < 26 ;i++){             if (Node[now].child[i] != 0 ){                 int  nxt = Node[now].child[i];                 Node[nxt].fail = Node[Node[now].fail].child[i];                 q.push (nxt);             }             else  Node[now].child[i] = Node[Node[now].fail].child[i];         }     } } void  insert (char  *s)     int  len = strlen (s);     int  now = 0 ;     for (int  i = 0 ;i < len;i++){         if (Node[now].child[s[i] - 'a' ] == 0 ){             Node[now].child[s[i] - 'a' ] = ++cnt;             Node[cnt].init ();         }         now = Node[now].child[s[i] - 'a' ];     }     Node[now].val += w; } int  main ()     cin>>n;     for (int  i = 1 ;i <= n;i++) {         cin>>s>>w;         insert (s);     }     cin>>l;     getfail ();     mst (f,0 );     for (int  i = 0 ;i <= cnt;i++){         f[1 ][i] = f[2 ][i] = -INF;     }     f[1 ][0 ] = 0 ;     for (int  i = 1 ;i <= l;i++){         for (int  j = 0 ;j <= cnt;j++){             if (f[1 ][j] == -INF) continue ;             for (int  k = 0 ;k < 26 ;k++){                 int  nxt = Node[j].child[k];                 f[2 ][nxt] = max (f[2 ][nxt],f[1 ][j] + Node[nxt].val);             }         }         for (int  j = 0 ;j <= cnt;j++) f[1 ][j] = f[2 ][j];     }     ll ans = 0 ;     for (int  i = 0 ;i <= cnt;i++) ans = max (ans,f[1 ][i]);     cout<<ans<<endl;     return  0 ; } 
I - qh与复读机IX 
I、给出一堆模式串,要求求出长度小于等于$L$并且包含其中任意一个字符串为子串的字符串的总类数量
 
AC自动机 矩阵乘法 快速幂
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 struct  acnode {    int  child[26 ];     int  val;     int  fail;          void  init ()          for (int  i = 0 ;i < 26 ;i++) child[i] = 0 ;         fail = 0 ;         val = 0 ;     } }Node[1000007 ]; struct  matrix {    ll num[250 ][250 ];     ll w,h;     matrix operator  * (const  matrix& a) const {         matrix res;         mst (res.num,0 );         res.h = h;         res.w = a.w;         for (int  i = 1 ;i <= h;i++){             for (int  j = 1 ;j <= a.w;j++){                 for (int  k = 1 ;k <= w;k++){                     res.num[i][j] = (res.num[i][j] + num[i][k] * a.num[k][j] % mod) % mod;                 }             }         }         return  res;     }     void  init (ll hh,ll ww)          h = hh;         w = ww;         mst (num,0 );         for (int  i = 1 ;i <= h;i++) num[i][i] = 1 ;     } }; ll n,l,cnt = 0 ; char  ss[1000 ];matrix f,x; ll ans; matrix MatrixQuickMod (const  matrix& a,ll b)  {    matrix t = a,res;     res.init (a.h,a.w);     if (b <= 0 ) return  res;     while (b){         if (b & 1 ) res = res * t;         t = t * t;         b >>= 1 ;     }     return  res; } void  insert (char  *s)     int  len = strlen (s);     int  now = 0 ;     for (int  i = 0 ;i < len;i++){         if (Node[now].child[s[i] - 'a' ] == 0 ){             Node[now].child[s[i] - 'a' ] = ++cnt;             Node[cnt].init ();         }         now = Node[now].child[s[i] - 'a' ];     }     Node[now].val = 1 ; } void  getfail ()     queue<int > q;     for (int  i = 0 ;i < 26 ;i++){         if (Node[0 ].child[i] != 0 ){             Node[Node[0 ].child[i]].fail = 0 ;             q.push (Node[0 ].child[i]);         }     }     while (!q.empty ()){         int  now = q.front ();         q.pop ();         if (Node[Node[now].fail].val == 1 ) Node[now].val = 1 ;         for (int  i = 0 ;i < 26 ;i++){             if (Node[now].child[i] != 0 ){                 int  nxt = Node[now].child[i];                 Node[Node[now].child[i]].fail = Node[Node[now].fail].child[i];                 q.push (Node[now].child[i]);             }             else  Node[now].child[i] = Node[Node[now].fail].child[i];         }     } } int  main ()     cin>>n;     for (int  i = 1 ;i <= n;i++){         cin>>ss;         insert (ss);     }     cin>>l;     getfail ();     cnt++;     f.w = f.h = cnt + 1 ;     for (int  i = 0 ;i < cnt;i++){         for (int  j = 0 ;j < 26 ;j++){             if (Node[Node[i].child[j]].val == 0 ) f.num[i + 1 ][Node[i].child[j] + 1 ]++;          }     }     for (int  i = 0 ;i <= cnt;i++) f.num[i + 1 ][cnt + 1 ] = 1 ;     f = MatrixQuickMod (f,l);     ans = 0 ;     for (int  i = 1 ;i <= cnt + 1 ;i++) ans = (ans + f.num[1 ][i]) % mod;     f.num[1 ][1 ] = 26 ;     f.num[2 ][1 ] = 0 ;     f.num[1 ][2 ] = 1 ;     f.num[2 ][2 ] = 1 ;     f.w = f.h = 2 ;     f = MatrixQuickMod (f,l + 1 );     ans = f.num[1 ][2 ] - ans;     ans = (ans + mod) % mod;     cout<<ans<<endl;     return  0 ; } 
J - qh与复读机X 
J、给出一堆模式串,求出每个模式串在所有的模式串中出现的次数
 
AC自动机 SAM然后复杂度的话。。。自动机的复杂度我算不来(逃后缀自动机txdy!
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 char  s1[maxn],s2[maxn];int  len2 = 0 ;int  len[maxn],ans[maxn],sum[maxn],tmp[maxn],ccnt[maxn];int  n;int  last = 1 ,cnt = 1 ;int  ch[maxn][27 ],fa[maxn<<1 ],l[maxn<<1 ];void  insert (int  c)     int  p=last,np=++cnt;     last=np,l[np]=l[p]+1 ;     ccnt[np] = 1 ;     for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;     if (!p) fa[np]=1 ;     else {         int  q=ch[p][c];         if (l[q]==l[p]+1 ) fa[np]=q;         else {             int  nq=++cnt;l[nq]=l[p]+1 ;             memcpy (ch[nq],ch[q],sizeof (ch[q]));             fa[nq]=fa[q];fa[q]=fa[np]=nq;             for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;         }     } } void  cal ()     for (int  i = 1 ;i <= cnt;i++) sum[l[i]]++;     for (int  i = 1 ;i <= cnt;i++) sum[i] += sum[i - 1 ];     for (int  i = 1 ;i <= cnt;i++) tmp[sum[l[i]]--] = i;     for (int  i = cnt;i;i--) ccnt[fa[tmp[i]]] += ccnt[tmp[i]]; } int  main ()     cin>>n;     for (int  i = 1 ;i <= n;i++){         cin>>s1;         len[i] = strlen (s1);         for (int  j  = 0 ;j < len[i];j++) insert (s2[++len2] = s1[j] - 'a' );         insert (s2[++len2] = 26 );     }     cal ();     len2 = 0 ;     for (int  i = 1 ;i <= n;i++){         int  x = 1 ;         for (int  j = 0 ;j < len[i];j++)  x = ch[x][s2[++len2]];         ans[i] = ccnt[x];         ++len2;     }     for (int  i = 1 ;i <= n;i++) cout<<ans[i]<<endl; 	return  0 ; } 
K - qh与复读机XI 
K、给出一个字符串$S$,要求输出长度为$1到|S|$的出现次数最多的子串的数量
 
SAM 基数排序``right集合 Parent树
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 char  s1[2000007 ];int  len = 0 ,ans[2000007 ],sum[2000007 ],f[2000007 ];int  id[2000007 ];int  last = 1 ,cnt = 1 ;int  ch[maxn][26 ],fa[maxn<<1 ],l[maxn<<1 ];void  insert (int  c)     int  p=last,np=++cnt;     last=np,l[np]=l[p]+1 ;     for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;     if (!p) fa[np]=1 ;     else {         int  q=ch[p][c];         if (l[q]==l[p]+1 ) fa[np]=q;         else {             int  nq=++cnt;l[nq]=l[p]+1 ;             memcpy (ch[nq],ch[q],sizeof (ch[q]));             fa[nq]=fa[q];fa[q]=fa[np]=nq;             for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;         }     }     f[np]++; } void  build (int  n)     for (int  i = 1 ;i <= n;i++) insert (s1[i] - 'a' ); } int  main ()     cin>>s1 + 1 ;     len = strlen (s1 + 1 );     build (len);     for (int  i = 1 ;i <= cnt;i++) sum[l[i]]++;     for (int  i = 1 ;i <= len;i++) sum[i] += sum[i - 1 ];     for (int  i = 1 ;i <= cnt;i++) id[sum[l[i]]--] = i;     for (int  i = cnt;i;i--) f[fa[id[i]]] += f[id[i]];     for (int  i = 1 ;i <= cnt;i++) ans[l[i]] = max (ans[l[i]],f[i]);     for (int  i = len;i;i--) ans[i] = max (ans[i + 1 ],ans[i]);     for (int  i = 1 ;i <= len;i++) cout<<ans[i]<<" " ;      return  0 ; } 
L - qh与复读机XII 
L、给出一个字符串$ S $,然后给出$ q $个询问,每个询问对应输出$S[l_1,r_1]$在$S[l_2,r_2]$中的出现次数
 
后缀自动机 线段树合并 倍增 right集合 Parent树什么好(po)题想了我三天时间倍增算法,先把$S[1,i]$能到达的结点位置预处理出来,实际上就是标记一下last的位置。。set的insert暴力搞?复杂度太大,启发式合并也救不了。。。。pb_ds的红黑树join?不行,区间不能相交(事后xyy给我说可以启发式合并一个一个插入是能保证复杂度的线段树合并
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 93 94 95 96 97 98 99 char  s1[maxn];int  len = 0 ;int  last = 1 ,cnt = 1 ;int  ch[maxn][26 ],fa[maxn],l[maxn];int  id[maxn];int  f[maxn][20 ];int  n,q,l1,r1,l2,r2;queue<int > Q; int  lchild[maxn<<3 ],rchild[maxn<<3 ],rt[maxn<<3 ],sum[maxn<<3 ];int  c[maxn],a[maxn],in[maxn];int  tot = 0 ;void  modify (int  &root,int  lp,int  rp,int  x)     if (!root) root = ++tot;     if (lp == rp) {         sum[root] = 1 ;         return  ;     }     int  mid = (lp + rp)>>1 ;     if (x <= mid) modify (lchild[root],lp,mid,x);     else  modify (rchild[root],mid + 1 ,rp,x);     sum[root] = sum[lchild[root]] + sum[rchild[root]]; } int  merge (int  x,int  y)     if (!x || !y) return  x^y;     int  p = ++tot;     lchild[p] = merge (lchild[x],lchild[y]);     rchild[p] = merge (rchild[x],rchild[y]);     sum[p] = sum[x] + sum[y];     return  p; } int  query (int  root,int  lp,int  rp,int  L,int  R)     if (L <= lp && rp <= R) return  sum[root];     int  mid = (lp + rp) >> 1 ;     if (R <= mid) return  query (lchild[root],lp,mid,L,R);     else  if (L > mid) return  query (rchild[root],mid + 1 ,rp,L,R);     else  return  (query (lchild[root],lp,mid,L,R) + query (rchild[root],mid + 1 ,rp,L,R)); } int  insert (int  c)     int  p=last,np=++cnt;     last=np,l[np]=l[p]+1 ;     in[np] = 1 ;     for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;     if (!p) fa[np]=1 ;     else {         int  q=ch[p][c];         if (l[q]==l[p]+1 ) fa[np]=q;         else {             int  nq=++cnt;l[nq]=l[p]+1 ;             memcpy (ch[nq],ch[q],sizeof (ch[q]));             fa[nq]=fa[q];fa[q]=fa[np]=nq;             for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;         }     }     return  last; } void  build (int  n)     for (int  i = 1 ;i <= n;i++) id[i] = insert (s1[i] - 'a' ); } int  main ()     cin>>n>>q;     cin>>s1 + 1 ;     build (n);     for (int  i = 1 ;i <= cnt;i++) c[l[i]]++;     for (int  i = 1 ;i <= cnt;i++) c[i] += c[i - 1 ];     for (int  i = 1 ;i <= cnt;i++) a[c[l[i]]--] = i;     for (int  i = cnt;i;i--){         int  pos = a[i];         if (in[pos]) modify (rt[pos],1 ,n,l[pos]);         rt[fa[pos]] = merge (rt[fa[pos]],rt[pos]);         f[pos][0 ] = fa[pos];     }     for (int  j = 1 ;j <= 18 ;j++){         for (int  i = 1 ;i <= cnt;i++){             f[i][j] = f[f[i][j - 1 ]][j - 1 ];         }     }     for (int  i = 1 ;i <= q;i++){         int  ans = 0 ;         cin>>l1>>r1>>l2>>r2;         int  len1 = r1 - l1 + 1 ;         int  pos = id[r1];         for (int  j = 18 ;j >=0 ;j--) if (l[f[pos][j]] >= len1) pos = f[pos][j];         int  lp = l2 + len1 - 1 ,rp = r2;         if (lp > rp) ans = 0 ;         else  ans = query (rt[pos],1 ,n,lp,rp);         printf ("%d\n" ,ans);     }     return  0 ; } 
M - 一切的开始,世界树的测验 
M、给出$ n $个数,可以有$ k $次机会将一个数改成$\sum _{ i = 1} ^ {x} i$,求选出若干个数字可以得到$ s $的方案数
 
dfs meet in middle又是您,您出的题可卡死我啰
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 long  long  a[30 ];long  long  b[30 ];ll n,k,s,mid; ll ans = 0 ; map<ll,ll> M[30 ]; void  dfs1 (ll sum,ll cur,ll cnt) 	if (cur == mid + 1 ){ 		if (M[cnt][sum] == 0 ) M[cnt][sum] = 1 ; 		else  M[cnt][sum] ++; 		return  ; 	} 	ll tmp = (a[cur] + 1 ) * a[cur] / 2 ; 	dfs1 (sum,cur + 1 ,cnt); 	if (a[cur] + sum <= s) dfs1 (sum + a[cur],cur + 1 ,cnt); 	if (cnt < k && tmp + sum <= s) dfs1 (sum + tmp,cur + 1 ,cnt + 1 ); } void  dfs2 (ll sum,ll cur,ll cnt) 	if (cur == n + 1 ){ 		for (int  i = 0 ;i + cnt <= k;i++){ 			if (M[i].count (s - sum)) ans += M[i][s - sum]; 		} 		return  ; 	} 	ll tmp = (a[cur] + 1 ) * a[cur] / 2 ; 	dfs2 (sum,cur + 1 ,cnt); 	if (a[cur] + sum <= s) dfs2 (sum + a[cur],cur + 1 ,cnt); 	if (cnt < k && tmp + sum <= s) dfs2 (sum + tmp,cur + 1 ,cnt + 1 ); } int  main () 	cin>>n>>k>>s; 	for (int  i = 1 ;i <= n;i++) cin>>a[i]; 	mid = n >> 1 ;     dfs1 (0 ,1 ,0 );     dfs2 (0 ,mid + 1 ,0 ); 	cout<<ans<<endl; 	return  0 ; } 
N - 第一个征程,噩梦的开始 
N、给出一个地图以及限制条件,输出最多能到达的位置数量
 
BFS
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 int  n,m,x,y;int  xx,yy;struct  node {	int  x,y; 	int  l,r; 	node (int  posx,int  posy,int  posl,int  posr):x (posx),y (posy),l (posl),r (posr){} }; int  ans = 1 ;char  mmp[2500 ][2500 ];bool  vis[2500 ][2500 ];void  bfs () 	deque<node> Q; 	Q.push_back (node (x,y - 1 ,xx,yy)); 	memset (vis,0 ,sizeof (vis)); 	vis[x][y - 1 ] = 1 ; 	while (!Q.empty ()){ 		node cur = Q.front (); 		Q.pop_front (); 		if (cur.y + 1  < m && mmp[cur.x][cur.y + 1 ] != '*'  && !vis[cur.x][cur.y + 1 ] && cur.r != 0 ){ 			vis[cur.x][cur.y + 1 ] = 1 ; 			ans++; 			Q.push_back (node (cur.x,cur.y + 1 ,cur.l,cur.r - 1 )); 		} 		if (cur.y - 1  >= 0  && mmp[cur.x][cur.y - 1 ] != '*'  && !vis[cur.x][cur.y - 1 ] && cur.l != 0 ){ 			vis[cur.x][cur.y - 1 ] = 1 ; 			ans++; 			Q.push_back (node (cur.x,cur.y - 1 ,cur.l - 1 ,cur.r)); 		} 		if (cur.x - 1  >= 1  && mmp[cur.x - 1 ][cur.y] != '*'  && !vis[cur.x - 1 ][cur.y]){ 			vis[cur.x - 1 ][cur.y] = 1 ; 			ans++; 			Q.push_front (node (cur.x - 1 ,cur.y,cur.l,cur.r)); 		} 		if (cur.x + 1  <= n && mmp[cur.x + 1 ][cur.y] != '*'  && !vis[cur.x + 1 ][cur.y]){ 			vis[cur.x + 1 ][cur.y] = 1 ; 			ans++; 			Q.push_front (node (cur.x + 1 ,cur.y,cur.l,cur.r)); 		} 	} 	cout<<ans<<endl; } int  main () 	cin>>n>>m>>x>>y>>xx>>yy; 	for (int  i = 1 ;i <= n;i++){ 		cin>>mmp[i]; 	} 	bfs (); 	return  0 ; } 
O - 第二个征程,拔起剪枝哀伤 
O、给定$n$个数,求出一个序列使得这n个数均可以由所得序列中的数作差得到
 
dfs 迭代加深
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 #include <cstdio>  #include <iostream>  #include <cstring>  #include <string>  #include <algorithm>  using  namespace  std;#define  mst(a,b) memset(a,b,sizeof(a)) long  long  n,a[60 ],ans[60 ];int  dep = 3 ;bool  dfs (int  cur,long  long  statu) 	if (cur == dep){ 		ans[cur] = a[n]; 		for (int  k = 1 ;k <= cur - 1 ;k++){ 			int  tmp = a[n] - ans[k]; 			int  pos = lower_bound (a + 1 ,a + n + 1 ,tmp) - a; 			if (a[pos] == tmp){ 				statu = statu | (1ll  << (pos - 1 )); 			} 		} 		return  statu == (1ll  << n) - 1 ; 	} 	for (int  i = 1 ;i <= cur - 1 ;i++){ 		for (int  j = 1 ;j <= n - 1 ;j++){ 			if (statu & (1ll  << (j - 1 ))) continue ; 			int  tmp = ans[i] + a[j]; 			if (tmp <= ans[cur - 1 ] || tmp >= a[n]) continue ; 			ans[cur] = tmp; 			long  long  nxt = statu; 			for (int  k = 1 ;k <= cur - 1 ;k++){ 				int  ttmp = tmp - ans[k]; 				int  pos = lower_bound (a + 1 ,a + n + 1 ,ttmp) - a; 				if (a[pos] == ttmp){ 					nxt = nxt | (1ll  << (pos - 1 )); 				} 			} 			if (dfs (cur + 1 ,nxt)) return  true ; 		} 	} 	return  false ; } int  main () 	cin>>n; 	for (int  i = 1 ;i <= n;i++) cin>>a[i]; 	sort (a + 1 ,a + n + 1 ); 	n = unique (a + 1 ,a + n + 1 ) - (a + 1 ); 	if (n == 1 ){ 		cout<<2 <<endl; 		cout<<0 <<" " <<a[1 ]<<endl; 		return  0 ; 	} 	mst (ans,0 ); 	while (!dfs (2 ,0 )){ 		dep++; 		mst (ans,0 ); 	} 	cout<<dep<<endl; 	for (int  i = 1 ;i <= dep;i++) cout<<ans[i]<<" " ; 	return  0 ; } 
P - 征程的结束,吉安娜 
P、先给出一个01矩阵,0表示不能移动的建筑,1表示能移动的建筑或者水晶,给出水晶坐标位置,以及两个坐标,问从一个坐标到另外一个坐标的最小时间花费
 
dfs spfa 最短路
先spfa预处理出可能的空白格子(就是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 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 93 94 95 96 97 98 99 100 101 102 103 104 105 #define  INF 1e8 #define  mst(a,b) memset(a,b,sizeof(a)) struct  pos {	int  x,y; 	pos (int  xx,int  yy):x (xx),y (yy){} }; int  mmp[40 ][40 ];int  n,m,q,ans;int  dist[40 ][40 ][40 ][40 ][5 ];int  vis[40 ][40 ][5 ];int  dirx[] = {0 ,1 ,0 ,-1 };int  diry[] = {1 ,0 ,-1 ,0 };int  a,b,c,d,ex,ey;bool  check (int  cx,int  cy) 	if (cx >= 1  && cx <= n && cy >= 1  && cy <= m && mmp[cx][cy]) return  true ; 	return  false ; } void  spfa (int  x,int  y,int  nowx,int  nowy,int  dir) 	bool  vvis[50 ][50 ]; 	queue<pos> q; 	q.push (pos (x,y)); 	dist[x][y][x][y][dir] = 0 ; 	mst (vvis,0 ); 	while (!q.empty ()){ 		pos now = q.front (); 		q.pop (); 		vvis[now.x][now.y] = 0 ; 		for (int  i = 0 ;i < 4 ;i++){ 			int  nxtx = now.x + dirx[i],nxty = now.y + diry[i]; 			if (check (nxtx,nxty) && (nxtx != nowx || nxty != nowy)){ 				if (dist[x][y][nxtx][nxty][dir] > dist[x][y][now.x][now.y][dir] + 1 ){ 					dist[x][y][nxtx][nxty][dir] = dist[x][y][now.x][now.y][dir] + 1 ; 					if (!vvis[nxtx][nxty]){ 						q.push (pos (nxtx,nxty)); 						vvis[nxtx][nxty] = 1 ; 					} 				} 			} 		} 	} } void  dfs (int  kx,int  ky,int  sx,int  sy,int  cnt,int  k) 	if (cnt >= ans) return  ; 	if (sx == ex && sy == ey) { 		ans = cnt; 		return  ; 	} 	if (vis[sx][sy][k] <= cnt) return  ;     vis[sx][sy][k] = cnt;     int  used[4 ] = {0 ,0 ,0 ,0 };     int  dir,len;     for (int  i = 0 ;i < 4 ;i++)     {         len = INF;         for (int  j = 0 ;j < 4 ;j ++)         {             int  x = sx + dirx[j],y = sy + diry[j];             if (check (x,y) && len > dist[x][y][kx][ky][(j+2 )%4 ] && !used[j])                 len = dist[x][y][kx][ky][(j+2 )%4 ],dir = j;         }         if (len != INF)         {             int  x = x = sx + dirx[dir],y = sy + diry[dir];             used[dir] = 1 ;             dfs (sx,sy,x,y,cnt+dist[x][y][kx][ky][(dir+2 )%4 ]+1 ,(dir+2 )%4 );         }        } } int  main () 	cin>>n>>m>>q; 	for (int  i = 1 ;i <= n;i++){ 		for (int  j = 1 ;j <= m;j++){ 			cin>>mmp[i][j]; 		} 	} 	mst (dist,0x3f ); 	for (int  i = 1 ;i <= n;i++){ 		for (int  j = 1 ;j <= m;j++){ 			if (!mmp[i][j]) continue ; 			for (int  k = 0 ;k < 4 ;k++){ 				int  nxtx = i + dirx[k]; 				int  nxty = j + diry[k]; 				if (check (nxtx,nxty)){ 					spfa (i,j,nxtx,nxty,k); 				} 			} 		} 	} 	for (int  i = 1 ;i <= q;i++){ 		cin>>a>>b>>c>>d>>ex>>ey; 		ans = INF; 		mst (vis,0x3f ); 		dfs (a,b,c,d,0 ,4 ); 		if (ans == INF) cout<<-1 <<endl; 		else  cout<<ans<<endl; 	} } 
Q - 猛男24点 
Q、两个人对弈,给出牌区的4张牌以及两个人的手牌,先手的获胜策略是到他的时候牌区能凑成24点,而后手的获胜条件是到他的时候牌区不能凑成24点,先手可以进行的操作是将自己的牌换到牌区里面,后手可以进行的操作是将牌区的牌与自己手中的黑牌进行交换。如果先手第一局不换牌,那么游戏会继续,反之游戏结束。
 
博弈 搜索 枚举
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 #define  eps 1e-6 struct  statu {	int  num[4 ]; 	statu (int  a,int  b,int  c,int  d){ 		num[0 ] = a; 		num[1 ] = b; 		num[2 ] = c; 		num[3 ] = d; 	} 	bool  operator  == (const  statu &a) const { 		for (int  i = 0 ;i < 4 ;i++){ 			if (num[i] == a.num[i]) continue ; 			else  return  false ; 		} 		return  true ; 	} 	bool  operator  < (const  statu &a) const { 		if (num[0 ] == a.num[0 ]){ 			if (num[1 ] == a.num[1 ]){ 				if (num[2 ] == a.num[2 ]){ 					return  num[3 ] < a.num[3 ]; 				} 				return  num[2 ] < a.num[2 ]; 			} 			return  num[1 ] < a.num[1 ]; 		} 		return  num[0 ] < a.num[0 ]; 	} }; struct  card {	bool  color; 	int  num; }; double  a[4 ];int  nows[4 ];card cards[10 ],card1[10 ],card2[10 ]; int  T,n,m;bool  used[10 ];map<int ,int > M; double  cal (double  a,double  b,int  k) 	if (k == 1 ) return  (a + b); 	else  if (k == 2 ) return  (a - b); 	else  if (k == 3 ) return  (a * b); 	else  if (k == 4 ) return  (a / b); } bool  check () 	for (int  i = 1 ;i<=4 ;i++){ 		for (int  j = 1 ;j <= 4 ;j++){ 			for (int  k = 1 ;k <= 4 ;k++){ 				double  tmp1,tmp2,tmp3; 				tmp1 = cal (a[0 ],a[1 ],i); 				tmp2 = cal (tmp1,a[2 ],j); 				tmp3 = cal (tmp2,a[3 ],k); 				if (fabs (tmp3 - 24 ) < eps) return  true ; 				tmp1 = cal (a[0 ],a[1 ],i); 				tmp2 = cal (a[2 ],a[3 ],k); 				tmp3 = cal (tmp1,tmp2,j); 				if (fabs (tmp3 - 24 ) < eps) return  true ; 				tmp1 = cal (a[1 ],a[2 ],j); 				tmp2 = cal (a[0 ],tmp1,i); 				tmp3 = cal (tmp2,a[3 ],k); 				if (fabs (tmp3 - 24 ) < eps) return  true ; 				tmp1 = cal (a[1 ],a[2 ],j); 				tmp2 = cal (tmp1,a[3 ],k); 				tmp3 = cal (tmp2,a[0 ],i); 				if (fabs (tmp3 - 24 ) < eps) return  true ; 				tmp1 = cal (a[2 ],a[3 ],k); 				tmp2 = cal (a[1 ],tmp1,j); 				tmp3 = cal (a[0 ],tmp2,i); 				if (fabs (tmp3 - 24 ) < eps) return  true ; 			} 		} 	} 	return  false ; } void  init () 	for (double  i = 1.0 ;i <= 10.0 ;i += 1.0 ){ 		a[0 ] = i; 		for (double  j = 1.0 ;j <= 10.0 ;j += 1.0 ){ 			a[1 ] = j; 			for (double  k = 1.0 ;k <= 10.0 ;k += 1.0 ){ 				a[2 ] = k; 				for (double  l = 1.0 ;l <= 10.0 ;l += 1.0 ){ 					a[3 ] = l; 					int  b[4 ]; 					if (check ()){ 					    for (int  i = 0 ;i < 4 ;i++) b[i] = a[i]; 					    sort (b,b + 4 ); 			            int  tmp = 0 ; 				        for (int  i = 0 ;i < 4 ;i++) tmp = tmp * 11  + b[i]; 						if (M[tmp] == 1 ) continue ; 				        M[tmp] = 1 ; 					} 				} 			} 		} 	} } bool  find (statu x) 	int  b[4 ]; 	int  tmp = 0 ; 	for (int  i = 0 ;i < 4 ;i++) b[i] = nows[i]; 	sort (b,b + 4 );     for (int  i = 0 ;i < 4 ;i++) tmp = tmp * 11  + b[i];     if (M[tmp] == 1 ) return  true ;     else  return  false ; } bool  dfs (bool  now,int  dep) 	bool  nowstatu = find (statu (nows[0 ],nows[1 ],nows[2 ],nows[3 ])); 	if (now == 0 ){ 		if (nowstatu){ 			if (dep != 1  || dfs (!now,dep + 1 )) return  true ; 		} 		for (int  i = 1 ;i <= n;i++){ 			if (!used[i]){ 				for (int  j = 1 ;j <= 4 ;j++){ 					swap (card1[i],cards[j]); 					nows[j - 1 ] = cards[j].num; 					used[i] = 1 ; 					bool  flag = dfs (!now,dep + 1 ); 					used[i] = 0 ; 					swap (card1[i],cards[j]); 					nows[j - 1 ] = cards[j].num; 					if (flag == true ) return  true ; 				} 			} 		} 		return  false ; 	} 	else { 		if (!nowstatu) return  false ; 		for (int  i = 1 ;i <= m;i++){ 			if (card2[i].color == 0 ){ 				for (int  j = 1 ;j <= 4 ;j++){ 					swap (card2[i],cards[j]); 					nows[j - 1 ] = cards[j].num; 					bool  flag = dfs (!now,dep + 1 ); 					swap (card2[i],cards[j]); 					nows[j - 1 ] = cards[j].num; 					if (flag == false ) return  false ; 				} 			} 		} 		return  true ; 	} } int  main () 	init (); 	cin>>T; 	for (int  i = 1 ;i <= T;i++){ 		memset (used,0 ,sizeof (used)); 		char  c; 		int  num; 		for (int  j = 1 ;j <= 4 ;j++){ 			cin>>num>>c; 			cards[j].num = num,cards[j].color = (c == 'b'  ? 0  : 1 ); 			nows[j - 1 ] = num; 		} 		cin>>n>>m; 		for (int  j = 1 ;j <= n;j++){ 			cin>>num>>c; 			card1[j].num = num,card1[j].color = (c == 'b'  ? 0  : 1 ); 		} 		for (int  j = 1 ;j <= m;j++){ 			cin>>num>>c; 			card2[j].num = num,card2[j].color = (c == 'b'  ? 0  : 1 ); 		} 		if (dfs (0 ,1 )) cout<<"You are MengNan!" <<endl; 		else  cout<<"Gan si 25zai!" <<endl; 	} 	return  0 ; } 
R - 如果早知道wf题也会被ak 
R、给出一个长度为$n$的字符串,求其最长偶回文子串的长度
 
Manacher
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 char  s1[30000007 ],s2[30000007 ];int  p[30000007 ],id = 1 ,mx = 1 ,ans = -1 ;int  init ()     s2[0 ] = '$' ;     s2[1 ] = '#' ;     int  j = 2 ;     int  len = strlen (s1);     for (int  i = 0 ;i<len;i++){         s2[j++] = s1[i];         s2[j++] = '#' ;     }     s2[j] = '\0' ;     return  j; } int  main ()     memset (p,0 ,sizeof (p));     int  n;     cin>>n;     cin>>s1;     int  len = init ();     for (int  i = 1 ;i<len;i++){         if (i < mx) p[i] = min (p[2  * id - i],mx - i);         else  p[i] = 1 ;         while (s2[i - p[i]] == s2[i + p[i]]){             p[i] ++;         }         if (s2[i] == '#' ) ans = max (ans,p[i] - 1 );         if (mx < i + p[i]){             id = i;             mx = i + p[i];         }     }     cout<<ans<<endl;     return  0 ; } 
S - 如果早知道wf题也会被ak - DLC1 
S、给出两个字符串,求这两个串的最长公共子串长度
 
SA SAM Height数组
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 char  s1[MAX],s2[MAX];int  sa[MAX],h[MAX],x[MAX],y[MAX],r[MAX],rk[MAX],m,ans = 0 ;int  len1,len2;bool  cmp (int  *r,int  a,int  b,int  len) 	return  r[a] == r[b] && r[a+len] == r[b+len]; } void  SA () 	m = M; 	for (int  i = 0 ;i<=m;i++) r[i] = 0 ; 	for (int  i = 0 ;i<len1;i++) r[x[i] = s1[i]] ++; 	for (int  i = 1 ;i<=m;i++) r[i] += r[i - 1 ]; 	for (int  i = len1 - 1 ;i>=0 ;i--) sa[--r[x[i]]] = i; 	for (int  j = 1 ,p = 1 ;j<=len1;j<<=1 ,m = p){ 		p = 0 ; 		for (int  i = len1 - j;i<len1;i++) y[p++] = i; 		for (int  i = 0 ;i<len1;i++) if (sa[i] >= j) y[p++] = sa[i] - j; 		for (int  i = 0 ;i<=m;i++) r[i] = 0 ; 		for (int  i = 0 ;i<len1;i++) r[x[i]] ++; 		for (int  i = 0 ;i<=m;i++) r[i] += r[i - 1 ]; 		for (int  i = len1 - 1 ;i>=0 ;i--) sa[--r[x[y[i]]]] = y[i]; 		swap (x,y); 	    p = 1 ; 	    x[sa[0 ]] = 0 ; 	    for (int  i = 1 ;i<len1;i++) x[sa[i]] = cmp (y,sa[i-1 ],sa[i],j)?p-1 :p++; 	}     int  j,k = 0 ;     for (int  i = 0 ;i<len1;i++) rk[sa[i]] = i;     for (int  i = 0 ;i<len1;h[rk[i++]] = k)     for (k?k--:0 ,j = sa[rk[i] - 1 ];s1[i + k] == s1[j + k];k++); } int  main () 	cin>>s1>>s2; 	len1 = strlen (s1); 	len2 = strlen (s2); 	s1[len1] = '$' ; 	for (int  i = 0 ;i<len2;i++) s1[i + len1 + 1 ] = s2[i];     int  tmp = len1; 	len1 = len1+len2+1 ;     len2 = tmp;     SA ();     for (int  i = 0 ;i<len1;i++){     	if (h[i] > 1 ){     		if (min (sa[i],sa[i-1 ]) < len2 && max (sa[i-1 ],sa[i]) > len2){     			if (ans < h[i]) ans = h[i];     		}     	}     }     cout<<ans<<endl;     return  0 ; }