【学习】字符串的各种
感觉字符串很厉害啊。。。然而上次znz大神上课的时候并没有听懂就弃疗惹
感觉现在根本做不出字符串相关得怪窝?
蒟蒻还需努力哎╮(╯▽╰)╭
求不被怒D
然而这里是个坑
大家快去膜lbn! 传送门: http://lbn187.is-programmer.com/posts/111869.html
nodes:原来的已经被修改丢掉辣TAT 所以时间点鬼畜的大家不要介意辣(╯‵□′)╯︵┻━┻
update 20160808: 感觉自己之前学的真是too young too simple啊
所以好好装修了一下QAQ
HASH&KMP
一直感觉kmp好难理解的,尤其是那个奇奇怪怪的next数组
但好像lbn上完课后感觉好多辣
又有一种。。。HASH好大啊的即视感
POI 2010 Beads
模拟串长直接暴力上啦
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;
#define pb push_back
#define NN 1000005
typedef unsigned long long ULL;
const ULL B = 999983ull;
map <ULL,bool> mp;
vector <int> k;
int n,mx,a[NN];
ULL mul[NN],s1[NN],s2[NN];
ULL Ha(int l,int r)
{
ULL tmp;
if (l <= r)
tmp = s1[r] - s1[l-1] * mul[r-l+1];
else tmp = s2[r] - s2[l+1] * mul[l-r+1];
return tmp;
}
void Solve(int xx)
{
if (mx * xx > n) return;
int ans = 0;
mp.clear();
for (int i=1;i<=n;i+=xx)
if (i+xx-1 <= n)
{
ULL tmp = Ha(i,i+xx-1) * Ha(i+xx-1,i);
if (mp[tmp]) continue;
else ans ++, mp[tmp] = 1;
}
if (ans > mx) mx = ans, k.clear();
if (ans == mx) k.pb(xx);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
mul[0] = 1;
for (int i=1;i<=n;++i) mul[i] = mul[i-1] * B;
for (int i=1;i<=n;++i) s1[i] = s1[i-1] * B + a[i];
for (int i=n;i>=1;--i) s2[i] = s2[i+1] * B + a[i];
for (int i=1;i<=n;++i) Solve(i);
printf("%d %lu\n",mx,k.size());
for (int i=0;i<k.size();++i)
{
printf("%d",k[i]);
if (i<k.size()-1) printf(" ");
}
return 0;
}
POI2012 A Horrible Poem
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;
#define NN 500005
#define N 500000
typedef unsigned long long ULL;
const ULL B = 999983ull;
ULL sum[NN],mul[NN];
char ch[NN];
int n,l,r,len,check[NN]={0},pri[NN]={0},m;
void Get_P()
{
for (int i=2;i<=N;++i)
{
if (check[i] == 0) check[i] = i, pri[++pri[0]] = i;
for (int j=1;j<=pri[0] && i*pri[j]<=N;++j)
{
check[i*pri[j]] = pri[j];
if (i % pri[j] == 0) break;
}
}
}
bool Equal(int la,int ra,int lb,int rb)
{
int tmp1 = sum[ra] - sum[la-1] * mul[ra-la+1];
int tmp2 = sum[rb] - sum[lb-1] * mul[rb-lb+1];
return (tmp1 == tmp2);
}
int main()
{
Get_P();
scanf("%d",&n);
scanf("%s",ch+1);
for (int i=1;i<=n;++i)
sum[i] = sum[i-1] * B + ch[i];
mul[0] = 1;
for (int i=1;i<=n;++i) mul[i] = mul[i-1] * B;
scanf("%d",&m);
while (m--)
{
scanf("%d%d",&l,&r);
len = r-l+1;
for (int i=len;i>1;)
{
int j = check[i];
while (len%j==0 && Equal(l,r-len/j,l+len/j,r)) len/=j;
while (i%j == 0) i/=j;
}
printf("%d\n",len);
}
return 0;
}
POI2006 Periods of Words
KMP好玩啊
next数组资磁哦
#include <bits/stdc++.h>
using namespace std;
#define NN 1001000
int n,k,ne[NN]={0};
long long ans=0ll;
char ch[NN];
int main()
{
scanf("%d",&n);
scanf("%s",ch+1);
for (int i=2;i<=n;++i)
{
for (;k && ch[k+1] ^ ch[i];k = ne[k]);
if (ch[k+1] == ch[i]) ++k;
ne[i] = k;
}
for (int i=1;i<=n;++i)
{
while (ne[ne[i]]) ne[i] = ne[ne[i]];
}
for (int i=1;i<=n;++i)
{
if (ne[i] != 0) ans += i-ne[i];
}
printf("%lld\n",ans);
return 0;
}
BZOJ3207 花神的嘲讽计划I
自爆辣
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
#define LL long long
#define NN 200005
#define MM 8000005
#define INF 18446744073709551615UL
int n,m,K,cnt = 0,val[NN],b[NN],rt[NN],sum[MM],a[MM][2];
unsigned LL H[NN],mod = 1UL;
void Ins(int xx,int &yy,unsigned LL val)
{
yy = ++cnt;
int tmp = yy;
sum[yy] = sum[xx] + 1;
unsigned LL l = 0, r = INF, mid;
while (l!=r)
{
mid = l/2 + r/2;
if ((l&1) && (r&1)) ++ mid;
int t = 0;
if (val > mid) t = 1,l = mid+1; else r = mid-1;
a[yy][t] = ++cnt;
a[yy][t^1] = a[xx][t^1];
xx = a[xx][t] ,yy = a[yy][t], sum[yy] = sum[xx] +1;
}
yy = tmp;
}
bool Query(int xx,int yy,unsigned LL val)
{
unsigned LL l = 0,r = INF,mid;
while (l!=r)
{
mid = l/2 + r/2;
if ((l&1) && (r&1)) ++mid;
int t = 0;
if (val > mid) t = 1, l = mid+1; else r = mid-1;
xx = a[xx][t] ,yy = a[yy][t];
}
return (sum[yy] - sum[xx]) != 0;
}
int main()
{
n = read(), m = read(), K = read();
for (int i=1;i<=n;++i) val[i] = read();
for (int i=1;i<=n;++i) H[i] = H[i-1] * 107+ val[i];
for (int i=1;i<=K;++i) mod *= 107;
for (int i=K;i<=n;++i) Ins(rt[i-1],rt[i],H[i]-H[i-K]*mod);
int x,y;
while (m--)
{
x = read(), y = read();
for (int i=1;i<=K;++i) b[i] = read();
unsigned LL now = 0;
for (int i=1;i<=K;++i) now = now *107 + b[i];
if (Query(rt[x+K-2],rt[y],now)) puts("No"); else puts("Yes");
}
return 0;
}
BZOJ-1009 [HNOI2008]GT考试
感觉是好久以前做的题了
当时的姿势水平只能看题解辣
好长的一段大家就去膜hzwer吧 http://hzwer.com/2955.html
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
string s;
int n,m,mod,ans;
int p[30],f[30][30],a[30][30],b[30][30];
void doing(int xx)
{
if (xx>3) doing(xx/2);
if (xx==1) return;
memset(a,0,sizeof(a));
for (int i=0;i<m;++i)
for (int j=0;j<m;++j)
for (int k=0;k<m;++k)
a[i][j]=(a[i][j]+f[i][k]*f[k][j])%mod;
memcpy(f,a,sizeof(a));
if (xx%2==1)
{
memset(a,0,sizeof(a));
for (int i=0;i<m;++i)
for (int j=0;j<m;++j)
for (int k=0;k<m;++k)
a[i][j]=(a[i][j]+f[i][k]*b[k][j])%mod;
memcpy(f,a,sizeof(f));
}
return;
}
int main()
{
scanf("%d%d%d",&n,&m,&mod);
memset(p,0,sizeof(p));
memset(f,0,sizeof(f));
memset(b,0,sizeof(b));
cin>>s;
s=" "+s;
for (int i=2;i<s.length();i++)
{
int xx=p[i-1];
while (s[i]!=s[xx+1]&&xx!=0) xx=p[xx];
if (s[i]==s[xx+1]) p[i]=xx+1;
}
for (int i=0;i<s.length()-1;++i)
{
for (int j=0;j<=9;++j)
{
int xx=i;
while (xx!=0&&j!=s[xx+1]-'0') xx=p[xx];
if (j==s[xx+1]-'0') f[i][xx+1]++;
else f[i][0]++;
}
}
memcpy(b,f,sizeof(f));
doing(n);
ans=0;
for(int i=0;i<m;++i) ans=(ans+f[0][i])%mod;
printf("%d\n",ans%mod);
return 0;
}
Manacher
马拉车这个鬼畜的名字是谁取的啊!(╯‵□′)╯︵┻━┻
BZOJ-2160 [2011集训队互测]拉拉队排练
先用Manacher求出数组后
用差分计算每一个长度的字符串出现的次数
暴力计算就好了~~
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define mod 19930726ll
#define NN 2000500
char ch[NN];
LL ans,k,cnt=0ll,sum[NN]={0};
int mx,p,r[NN],n;
LL Pow(LL xx,LL yy)
{
LL sum=1ll;
for (xx%=mod;yy;xx=xx*xx%mod,yy>>=1) if (yy&1) sum=sum*xx%mod;
return sum;
}
int main()
{
scanf("%d%lld",&n,&k);
scanf("%s",ch+1);
ch[0] = '#', ch[n+1] = '&';
for (int i=1;i<=n;++i)
{
r[i] = (mx > i) ? min(r[2*p-i],mx-i) : 1;
while (ch[i+r[i]] == ch[i-r[i]]) r[i] ++;
if (r[i]+i > mx) mx = r[i] + i, p = i;
sum[1] ++ , sum[r[i]+1] --;
}
for (int i=2;i<=n;++i) sum[i] += sum[i-1];
ans = 1ll;
for (int i=n;i>=1;--i)
if (sum[i] + cnt <= k) ans = (ans * Pow(2*i-1,sum[i])) % mod, cnt += sum[i];
else
{
ans = (ans * Pow(2*i-1,k-cnt)) % mod, cnt = k;
break;
}
if (cnt < k) puts("-1"); else printf("%lld\n",ans);
return 0;
}
BZOJ-2565 [2012清华集训]最长双回文串
先插入‘#’
那么就可以算出l[i]表示以i为结尾的最左的回文串的中心
然后枚举每一个‘#’当做断点,然后更新答案~~~
#include <bits/stdc++.h>
using namespace std;
#define NN 200010
char c,ch[NN];
int r[NN],lm[NN],rm[NN],n=0,ans,mx,p;
void read()
{
for (c = getchar();c<'a' || c>'z';c = getchar());
ch[++n] = '#';
ch[++n] = c;
for (c = getchar();c>='a' && c<='z';ch[++n] = '#', ch[++n] = c, c = getchar());
ch[++n] = '#';
}
int main()
{
read();
mx = 0;
for (int i=1;i<=n;++i)
{
r[i] = (mx > i) ? min(r[2*p-i],mx-i+1) : 1;
while (ch[i+r[i]] == ch[i-r[i]] && i-r[i] >= 1 && i+r[i] <= n) ++r[i];
if (i+r[i]-1 > mx) mx = i+r[i]-1, p = i;
}
mx = r[0] = 0;
for (int i=1;i<=n;++i)
{
if (i+r[i]-1 > mx)
{
for (int j=mx+1;j<=i+r[i]-1;++j) lm[j] = i;
mx = i+r[i]-1;
}
if (mx == n) break;
}
mx = n+1;
for (int i=n;i>=1;--i)
{
if (i-r[i]+1 < mx)
{
for (int j=i-r[i]+1;j<=mx-1;++j) rm[j] = i;
mx = i-r[i]+1;
}
if (mx == 1) break;
}
for (int i=1;i<=n;++i)
if (ch[i] == '#')
{
int tmp = (rm[i]-i+1 + i-lm[i]+1) * 2 - 3;
if (tmp/2 > ans) ans = tmp/2;
}
printf("%d\n",ans);
return 0;
}
AC自动机
BZOJ-3172
| Descriprtion | 某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。 |
| Input |
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
|
| Output | 输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。 |
|
Sample Input |
3 a aa aaa |
| Sample Output |
6 3 1 |
AC自动机果题
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
#define NN 1000005
int n,pos[NN];
struct AC
{
int cnt,ne[NN][26],sum[NN],fail[NN],que[NN];
char ch[NN];
acm()
{ cnt=1; for (int i=0;i<26;++i) ne[0][i]=1; }
void Insert(int &pos)
{
int now=1;
scanf("%s",ch);
int len=strlen(ch);
for (int i=0;i<len;++i)
{
if (!ne[now][ch[i]-'a']) ne[now][ch[i]-'a']=++cnt;
now=ne[now][ch[i]-'a'];
sum[now]++;
}
pos=now;
}
void buildfail()
{
int head=0, tail=1;
que[0]=1, fail[1]=0;
while (head!=tail)
{
int now=que[head]; head++;
for (int i=0;i<26;++i)
{
int v=ne[now][i];
if (!v) continue;
int k=fail[now];
while (!ne[k][i]) k=fail[k];
fail[v]=ne[k][i];
que[tail++]=v;
}
}
for (int i=tail-1;i>=0;--i)
sum[fail[que[i]]]+=sum[que[i]];
}
}acm;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) acm.Insert(pos[i]);
acm.buildfail();
for (int i=1;i<=n;++i)
printf("%d\n",acm.sum[pos[i]]);
return 0;
}
BZOJ-2754
AC自动机模板+map、vector乱搞
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
#define pb push_back
#define NN 100005
using namespace std;
int n,m,ans1[NN],ans2[NN];
bool vis[NN],mark[NN];
vector<int> a[20005],st[NN],V,M;
map<int,int> ne[NN];
struct T
{
int cnt,fail[NN],que[NN];
T()
{
cnt=1;
for (int i=-1;i<=10000;++i) ne[0][i]=1;
fail[1]=0;
}
void Insert(int pos)
{
int l,x,now=1;
scanf("%d",&l);
for (int i=1;i<=l;++i)
{
scanf("%d",&x);
if (!ne[now][x]) ne[now][x]=++cnt;
now=ne[now][x];
}
st[now].pb(pos);
}
void buildfail()
{
int head=0,tail=1; que[0]=1;
while (head!=tail)
{
int now=que[head++];
for (map<int,int>::iterator i=ne[now].begin();i!=ne[now].end();++i)
{
int t=i->first,k=fail[now];
while (!ne[k][t]) k=fail[k];
fail[i->second]=ne[k][t];
que[tail++]=i->second;
}
}
}
void gets(int pos,int xx)
{
for (int i=xx;i;i=fail[i])
if (!vis[i])
{
vis[i]=1, V.pb(i);
for (int j=0;j<st[i].size();++j)
if (!mark[st[i][j]])
{
mark[st[i][j]]=1, M.pb(st[i][j]);
ans1[st[i][j]]++, ans2[pos]++;
}
}else break;
}
void solve(int xx)
{
int now=1;
for (int i=0;i<a[xx].size();++i)
{
int t=a[xx][i];
while (!ne[now][t]) now=fail[now];
now=ne[now][t], gets(xx,now);
}
for (int i=0;i<V.size();++i) vis[V[i]]=0;
for (int i=0;i<M.size();++i) mark[M[i]]=0;
V.clear(); M.clear();
}
}Trie;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
{
int l,x;
scanf("%d",&l);
while (l--) scanf("%d",&x), a[i].pb(x);
a[i].pb(-1);
scanf("%d",&l);
while (l--) scanf("%d",&x), a[i].pb(x);
}
for (int i=1;i<=m;++i) Trie.Insert(i);
Trie.buildfail();
for (int i=1;i<=n;++i) Trie.solve(i);
for (int i=1;i<=m;++i) printf("%d\n",ans1[i]);
for (int i=1;i<n;++i) printf("%d ",ans2[i]); printf("%d\n",ans2[n]);
return 0;
}
BZOJ-1030 JSOI2007 文本生成器
f[i][j]表示到第i个位置匹配自动机上第j个结点的方案数
感觉很多自动机上的DP都长这个样子
#include <bits/stdc++.h>
using namespace std;
const int mod = 10007;
const int NN = 6011;
int dp[101][NN],n,m,anss=1,ans=0;
char ch[110];
int cnt, ne[NN][26]={0},fail[NN],que[NN];
bool danger[NN];
void Clr() { cnt = 1; for (int i=0;i<26;++i) ne[0][i] = 1;}
void Insert()
{
int now = 1,len = strlen(ch),c;
for (int i=0;i<len;++i)
{
c=ch[i]-'A';
if (!ne[now][c]) ne[now][c] = ++cnt;
now = ne[now][c];
}
danger[now] = 1;
}
void Buildfail()
{
int head = 0, tail = 1; que[0] = 1, fail[1] = 0;
while (head != tail)
{
int now = que[head++];
for (int i=0;i<26;++i)
{
int v = ne[now][i]; if (!v) continue;
int k = fail[now]; while (!ne[k][i]) k = fail[k];
fail[v] = ne[k][i], que[tail++] = v;
if (danger[ne[k][i]]) danger[v] = 1;
}
}
}
void DP(int xx)
{
for (int i=1;i<=cnt;++i)
{
if (danger[i] || !dp[xx-1][i]) continue;
for (int j=0;j<26;++j)
{
int k = i;
while (!ne[k][j]) k = fail[k];
dp[xx][ne[k][j]] = (dp[xx][ne[k][j]] + dp[xx-1][i]) % mod;
}
}
}
int main()
{
Clr();
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
{
scanf("%s",ch);
Insert();
}
Buildfail();
dp[0][1] = 1;
for (int i=1;i<=m;++i) DP(i);
anss =1;
for (int i=1;i<=m;++i) anss = (anss * 26) % mod;
for (int i=1;i<=cnt;++i)
if (!danger[i]) ans = (ans + dp[m][i]) % mod;
printf("%d\n",(anss - ans + mod) % mod);
return 0;
}
BZOJ-1195 HNOI2006 最短母串
状压DP
其实类似于BFS辣
不过内存卡卡卡!!!
(lych:不卡内存的都不是正解
#include <bits/stdc++.h>
using namespace std;
const int NN = 601;
const int N = 1<<12;
char ch[110];
int cnt, ne[NN][26]={0},fail[NN],que[NN];
int dag[NN];
int la[NN*N],n,ans[NN],tot;
bool vis[NN][N];
short lac[NN*N],pre[NN*N],b[NN*N];
void Clr() { cnt = 1; for (int i=0;i<26;++i) ne[0][i] = 1;}
void Insert(int xx)
{
int now = 1, len = strlen(ch), c;
for (int i=0;i<len;++i)
{
if (!ne[now][c = ch[i]-'A']) ne[now][c] = ++cnt;
now = ne[now][c];
}
dag[now] |= (1<<(xx-1));
}
void Buildfail()
{
int head = 0, tail = 1; que[0] = 1, fail[1] = 0;
while (head != tail)
{
int now = que[head++];
for (int i=0;i<26;++i)
{
int v = ne[now][i];
if (!v)
{
ne[now][i] = ne[fail[now]][i];
continue;
}
int k = fail[now]; while (!ne[k][i]) k = fail[k];
fail[v] = ne[k][i], que[tail++] = v;
dag[v] |= dag[fail[v]];
}
}
}
int main()
{
scanf("%d",&n);
Clr();
for (int i=1;i<=n;++i)
{
scanf("%s",ch);
Insert(i);
}
Buildfail();
int head = 0, tail = 1;
b[0] = pre[0] = 0;
while (head != tail)
{
int u = b[head], now = pre[head];
if (now == (1<<n)-1) break;
for (int i=0;i<26;++i)
if (!vis[ne[u][i]][now|dag[ne[u][i]]])
{
lac[tail] = i, la[tail] = head, b[tail] = ne[u][i], pre[tail] = now|dag[ne[u][i]];
vis[ne[u][i]][pre[tail]] = 1;
tail++;
}
head++;
}
for (;head;head=la[head]) ans[++tot] = lac[head];
for (int i=tot-1;i>=1;--i) putchar('A'+ans[i]); puts("");
return 0;
}
BZOJ-2746 SDOI2014 数数
直接在AC自动机上造树然后呢 LCA!
之前把LCA都快忘了TAT
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007LL
#define pb push_back
typedef long long LL;
const int NN = 1000100;
int n,m;
char ch[NN];
int cnt, ne[NN][26]={0},dep[NN],fa[NN][22];
vector <int> pos[NN];
LL ans[NN];
void Clr()
{
cnt = 0; for (int i=0;i<26;++i) ne[0][i] = 0;
}
queue <int> que;
void Buildfail()
{
for (int i=0;i<26;++i)
if (ne[0][i])
{
que.push(ne[0][i]);
fa[ne[0][i]][0] = 0;
dep[ne[0][i]] = 1;
}
while (!que.empty())
{
int now = que.front(); que.pop();
for (int i=0;i<26;++i)
{
int v = ne[now][i];
if (!v)
{
ne[now][i] = ne[fa[now][0]][i]; continue;
}
int k = fa[now][0]; while (k && !ne[k][i]) k = fa[k][0];
que.push(v);
dep[v] = dep[ne[k][i]] + 1;
fa[v][0] = ne[k][i];
}
}
}
void Buildlca()
{
for (int j=1;j<20;++j)
for (int i=1;i<=cnt;++i)
fa[i][j] = fa[fa[i][j-1]][j-1];
}
int LCA(int xx,int yy)
{
if (dep[xx] < dep[yy]) swap(xx,yy);
int tmp = dep[xx] - dep[yy];
for (int i=0;i<=20;++i) if (tmp>>i & 1) xx = fa[xx][i];
for (int i=17;i>=0;--i) if (fa[xx][i] != fa[yy][i]) xx = fa[xx][i], yy = fa[yy][i];
return (xx == yy) ? ans[xx]:ans[fa[xx][0]];
}
int main()
{
Clr();
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%s",ch);
int len = strlen(ch);
int x = 0;
for (int j = 0; j < len; j++) {
int po = ch[j] - 'a';
if (!ne[x][po]) {
ne[x][po] = ++cnt;
LL ADD = ch[j] - 'a';
ans[cnt] = (ans[x]*26LL + ADD)%mod;
}
x = ne[x][po];
pos[i].push_back(x);
}
}
Buildfail();
Buildlca();
scanf("%d",&m);
int xa,xb,ya,yb;
while (m--)
{
scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
printf("%d\n",LCA(pos[xa][ya-1],pos[xb][yb-1]));
}
return 0;
}
BZOJ-2434 NOI2011 阿狸的打字机
感觉会语死早
更资磁:http://hzwer.com/5423.html
#include <bits/stdc++.h>
using namespace std;
int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
const int NN = 100005;
int n,m,tot =0,T,l[NN],r[NN],tr[NN<<1],head[NN],laq[NN],pos[NN],ans[NN];
char ch[NN];
struct FT
{
int v,ne;
}e[NN],q[NN];
int fail[NN],fa[NN],ne[NN][27],que[NN],cnt;
void Clr()
{
cnt = 1;
for (int i=0;i<26;++i) ne[0][i] = 1;
}
void Insert()
{
int now = 1, id = 0,c;
for (int i=0;i<n;++i)
if (ch[i] == 'P') pos[++id] = now;
else if (ch[i] == 'B') now = fa[now];
else
{
if (!ne[now][c=ch[i]-'a'])
{
ne[now][c] = ++ cnt;
fa[cnt] = now;
}
now = ne[now][c];
}
}
void Buildfail()
{
int head = 0, tail = 1; que[0] = 1, fail[1] = 0;
while (head != tail)
{
int now = que[head++];
for (int i=0;i<26;++i)
{
if (ne[now][i])
{
int v = ne[now][i];
int k = fail[now];
while (!ne[k][i]) k = fail[k];
fail[v] = ne[k][i];
que[tail++] = v;
}
}
}
}
void Build(int xx,int yy)
{
e[++tot].ne = head[xx], head[xx] = tot, e[tot].v = yy;
}
void DFS(int xx)
{
l[xx] = ++T;
for (int i=head[xx];i;i=e[i].ne) DFS(e[i].v);
r[xx] = ++T;
}
int lowbit(int xx) { return xx & -xx;}
void Add(int xx,int yy)
{
for (int i=xx;i<=T;i+=lowbit(i)) tr[i] += yy;
}
int query(int xx)
{
int sum =0;
for (int i=xx;i;i-=lowbit(i)) sum += tr[i]; return sum;
}
void Solve()
{
int now = 1, id = 0;
Add(l[1],1);
for (int i=0;i<n;++i)
{
if (ch[i] == 'P')
{
++id;
for (int x=laq[id];x;x=q[x].ne)
{
int tmp = pos[q[x].v];
ans[x] = query(r[tmp]) - query(l[tmp]-1);
}
}
else
if (ch[i] == 'B') Add(l[now],-1), now = fa[now];
else now = ne[now][ch[i]-'a'], Add(l[now],1);
}
}
int main()
{
scanf("%s",ch);
Clr();
n = strlen(ch);
Insert();
Buildfail();
for (int i=1;i<=cnt;++i) Build(fail[i],i);
m = read();
int x,y;
for (int i=1;i<=m;++i)
{
x = read(), y = read();
q[i].ne = laq[y];
laq[y] = i;
q[i].v = x;
}
DFS(0);
Solve();
for (int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}
后缀自动机
BZOJ-3998
| Descriprtion | 对于一个给定长度为N的字符串,求它的第K小子串是什么。 |
| Input |
第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。 |
| Output | 输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1 |
| Sample Input |
aabc 0 3 |
| Sample Output | aab |
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define NN 500050
#define MM 1000010
using namespace std;
int n,t,k;
char ch[NN];
struct SAM
{
int tot,la,a[MM][30],mx[MM],fa[MM],v[NN],q[MM],val[MM],sum[MM];
SAM(){ la=++tot;}
void extend(int xx)
{
int p=la,np=la=++tot;
mx[np]=mx[p]+1,val[np]=1;
while (!a[p][xx] && p) a[p][xx]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
int q=a[p][xx];
if (mx[p]+1==mx[q]) fa[np]=q;
else
{
int nq=++tot; mx[nq]=mx[p]+1;
memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q],fa[np]=fa[q]=nq;
while (a[p][xx]==q) a[p][xx]=nq,p=fa[p];
}
}
}
void pre()
{
for (int i=1;i<=tot;++i) v[mx[i]]++;
for (int i=1;i<=n;++i) v[i]+=v[i-1];
for (int i=tot;i;i--) q[v[mx[i]]--]=i;
for (int i=tot;i;i--)
{
int tmp=q[i];
if (t==1) val[fa[tmp]]+=val[tmp]; else val[tmp]=1;
}
val[1]=0;
for (int i=tot;i;i--)
{
int tmp=q[i]; sum[tmp]=val[tmp];
for (int j=0;j<26;++j) sum[tmp]+=sum[a[tmp][j]];
}
}
void dfs(int xx,int yy)
{
if (yy<=val[xx]) return;
yy-=val[xx];
for (int i=0;i<26;++i)
if (int tmp=a[xx][i])
{
if(yy<=sum[tmp])
{
putchar(i+'a'); dfs(tmp,yy); return;
}
yy-=sum[tmp];
}
}
}SAM;
int main()
{
scanf("%s",ch+1); n=strlen(ch+1);
scanf("%d%d",&t,&k);
for (int i=1;i<=n;++i) SAM.extend(ch[i]-'a');
SAM.pre();
if (k>=SAM.sum[1]) { puts("-1"); return 0;}
else SAM.dfs(1,k);
return 0;
}
BZOJ-3926
神奇的题目描述啊。。。感觉语文不好的后果来了
ZJOI的题目呢。。。马上省选了好虚。。强省蒟蒻滚粗无疑辣。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <string>
#define LL long long
#define MM 4000005
#define NN 100005
using namespace std;
LL ans;
int n,c,cc[NN],d[NN],tot=0,head[NN];
struct Edge
{
int ne,v;
}e[NN<<1];
void Build(int xx,int yy)
{
e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy;
e[++tot].ne=head[yy], head[yy]=tot, e[tot].v=xx;
}
struct SAM
{
int cnt,fa[MM],a[MM][10],mx[MM];
SAM(){cnt=1;}
int extend(int p,int c)
{
int np=++cnt; mx[np]=mx[p]+1;
while (!a[p][c] && p) a[p][c]=np, p=fa[p];
if (!p) fa[np]=1;
else
{
int q=a[p][c];
if (mx[p]+1==mx[q]) fa[np]=q;
else
{
int nq=++cnt;mx[nq]=mx[p]+1;
memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q], fa[np]=fa[q]=nq;
while (a[p][c]==q) a[p][c]=nq, p=fa[p];
}
}
return np;
}
void solve()
{
for (int i=1;i<=cnt;++i) ans+=mx[i]-mx[fa[i]];
}
}Sam;
void DFS(int x,int fa,int p)
{
int t=Sam.extend(p,cc[x]);
for (int i=head[x];i;i=e[i].ne)
if (e[i].v!=fa)
DFS(e[i].v,x,t);
}
int main()
{
scanf("%d%d",&n,&c);
for (int i=1;i<=n;++i) scanf("%d",&cc[i]);
int x,y;
for (int i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
Build(x,y);
d[x]++, d[y]++;
}
for (int i=1;i<=n;++i)
if (d[i]==1) DFS(i,0,1);
Sam.solve();
printf("%lld\n",ans);
return 0;
}
BZOJ-4199
唔。。2015年的NOI题目呢。。。别忘了考虑负数。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define LL long long
#define NN 600006
#define INF 2e18
using namespace std;
LL mav[NN],ma1[NN],ma2[NN],mi1[NN],mi2[NN],head[NN],n,m,a[NN],size[NN],ans[NN],tot=0;
bool vis[NN];
char ch[NN];
struct Edge
{
int v,ne,w;
}e[NN];
void Build(LL xx,LL yy,LL zz)
{
e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].w=zz;
}
struct SAM
{
LL cnt,la,ne[NN][26],fa[NN],mx[NN],t[NN],now,tmp,nx[NN];
SAM(){la=++cnt;}
void extend(int xx)
{
LL p=la,np=la=++cnt,c=ch[xx]-'a';
mx[np]=mx[p]+1, t[np]=xx;
while (!ne[p][c] && p) ne[p][c]=np, p=fa[p];
if (!p) fa[np]=1;
else
{
LL q=ne[p][c];
if (mx[p]+1==mx[q]) fa[np]=q;
else
{
LL nq=++cnt; mx[nq]=mx[p]+1;
memcpy(ne[nq],ne[q],sizeof(ne[q]));
fa[nq]=fa[q], fa[np]=fa[q]=nq;
while (ne[p][c]==q) ne[p][c]=nq, p=fa[p];
}
}
}
void DFS(LL xx,LL h)
{
if (t[xx]) ma1[xx]=mi1[xx]=a[t[xx]], size[xx]=1;
else ma1[xx]=-INF,mi1[xx]=INF, size[xx]=0;
ma2[xx]=-INF, mi2[xx]=INF;
for (LL i=head[xx];i;i=e[i].ne)
{
LL yy=e[i].v;
DFS(yy,h+e[i].w);
if (ma1[yy]>ma1[xx])
{
ma2[xx]=ma1[xx], ma1[xx]=ma1[yy];
if (ma2[yy]>ma2[xx]) ma2[xx]=ma2[yy];
}
else
if (ma1[yy]>ma2[xx]) ma2[xx]=ma1[yy];
if (mi1[yy]<mi1[xx])
{
mi2[xx]=mi1[xx], mi1[xx]=mi1[yy];
if (mi2[yy]<mi2[xx]) mi2[xx]=mi2[yy];
}
else
if (mi1[yy]<mi2[xx]) mi2[xx]=mi1[yy];
size[xx]+=size[yy], nx[xx]+=nx[yy];
}
now=-INF; tmp=(size[xx]*(size[xx]-1))/2;
if (size[xx]>=4)now=max(max(ma1[xx]*ma2[xx],mi1[xx]*mi2[xx]),max(ma1[xx]*mi2[xx],ma2[xx]*mi1[xx]));
else
if (size[xx]>=3) now=max(max(ma1[xx]*ma2[xx],mi1[xx]*mi2[xx]),ma1[xx]*mi1[xx]);
else
if (size[xx]>=2) now=ma1[xx]*ma2[xx];
if (now!=INF) ans[h]+=tmp-nx[xx], mav[h]=max(mav[h],now);
nx[xx]+=tmp-nx[xx];
}
}Sam;
int main()
{
scanf("%lld",&n);
scanf("%s",ch+1);
for (LL i=n;i;i--) Sam.extend(i);
vis[1]=1;
for (LL i=1;i<=Sam.cnt;++i)
if (Sam.t[i]&&!vis[i])
for (LL j=i;!vis[j];vis[j]=1,j=Sam.fa[j]) Build(Sam.fa[j],j,Sam.mx[j]-Sam.mx[Sam.fa[j]]);
for (LL i=0;i<=n;++i) mav[i]=-INF;
for (LL i=1;i<=n;++i) scanf("%lld",&a[i]);
Sam.DFS(1,0);
for (LL i=n-1;i>=0;--i) ans[i]=ans[i]+ans[i+1], mav[i]=max(mav[i],mav[i+1]);
for (LL i=0;i<n;++i)
{
if (mav[i]==-INF) mav[i]=0;
printf("%lld %lld\n",ans[i],mav[i]);
}
return 0;
}
后缀数组 SA
听说并没有什么卵用
听说可以被后缀自动机完美取代
反正板子太长了也不怎么想背
理解起来好像一样难qaq
BZOJ-1031
SA的题目,恶补字符串辣
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define NN 200010
using namespace std;
int sa[2][NN],rank[2][NN],v[NN],a[NN],len,k;
char ch[NN];
void Calsa(int sa[NN],int rank[NN],int SA[NN],int Rank[NN])
{
for (int i=1;i<=len;++i) v[rank[sa[i]]]=i;
for (int i=len;i>=1;--i)
if (sa[i]>k)
SA[v[rank[sa[i]-k]]--]=sa[i]-k;
for (int i=len-k+1;i<=len;++i) SA[v[rank[i]]--]=i;
for (int i=1;i<=len;++i)
Rank[SA[i]]=Rank[SA[i-1]]+(rank[SA[i-1]]!=rank[SA[i]] || rank[SA[i-1]+k]!=rank[SA[i]+k]);
}
void Work()
{
int p=0,q=1;
for (int i=1;i<=len;++i) v[a[i]]++;
for (int i=1;i<=256;++i) v[i]+=v[i-1];
for (int i=1;i<=len;++i) sa[p][v[a[i]]--]=i;
for (int i=1;i<=len;++i) rank[p][sa[p][i]]=rank[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
k=1;
for (k=1;k<len;p^=1,q^=1,k<<=1) Calsa(sa[p],rank[p],sa[q],rank[q]);
for (int i=1;i<=len;++i)
if (sa[p][i]<=len/2) printf("%c",ch[sa[p][i]+len/2-1]);
puts("");
}
int main()
{
scanf("%s",ch+1);
len=strlen(ch+1);
for (int i=1;i<=len;++i)
a[i]=int(ch[i]), a[i+len]=a[i], ch[i+len]=ch[i];
len<<=1;
Work();
return 0;
}C
BZOJ-3238
感觉后缀数组并不是正解。。时间好长(zhǎng)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define NN 500005
#define INF 0x3f3f3f3f
#define LL long long
int v[NN],a[NN],rank[2][NN],sa[2][NN],st[NN],l[NN],r[NN],len,top,h[NN],k;
LL ans;
char ch[NN];
void Calsa(int sa[NN],int rank[NN],int SA[NN],int Rank[NN])
{
for (int i=1;i<=len;++i) v[rank[sa[i]]]=i;
for (int i=len;i>=1;--i)
if (sa[i]>k) SA[v[rank[sa[i]-k]]--]=sa[i]-k;
for (int i=len-k+1;i<=len;++i) SA[v[rank[i]]--]=i;
for (int i=1;i<=len;++i)
Rank[SA[i]]=Rank[SA[i-1]]+(rank[SA[i-1]]!=rank[SA[i]] || rank[SA[i-1]+k]!=rank[SA[i]+k]);
}
void PreSA()
{
int p=1,q=0;
for (int i=1;i<=len;++i) v[a[i]]++;
for (int i=1;i<=30;++i) v[i]+=v[i-1];
for (int i=1;i<=len;++i) sa[p][v[a[i]]--]=i;
for (int i=1;i<=len;++i) rank[p][sa[p][i]]=rank[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]);
for (k=1;k<len;k<<=1,p^=1,q^=1) Calsa(sa[p],rank[p],sa[q],rank[q]);
for (int k=0,i=1;i<=len;++i)
{
int j=sa[p][rank[p][i]-1];
while (a[j+k]==a[i+k]) ++k;
h[rank[p][i]]=k; if (k>0) k--;
}
}
void Solve()
{
for (int i=1;i<=len;++i) ans+=(LL)i*(len-1);
h[0]=-INF;
for (int i=1;i<=len;++i)
{
while (h[i]<=h[st[top]]) top--;
if (st[top]==0) l[i]=1; else l[i]=st[top]+1;
st[++top]=i;
}
h[len+1]=-INF, top=0, st[0]=len+1;
for (int i=len;i;i--)
{
while (h[i]<h[st[top]]) top--;
if (st[top]==len+1) r[i]=len; else r[i]=st[top]-1;
st[++top]=i;
}
for (int i=1;i<=len;++i) ans-=2ll*(i-l[i]+1)*(r[i]-i+1)*h[i];
}
int main()
{
scanf("%s",ch+1);
len=strlen(ch+1);
for (int i=1;i<=len;++i) a[i]=ch[i]-'a'+1;
PreSA();
Solve();
printf("%lld\n",ans);
return 0;
}
回文自动机
BZOJ-3676
听说这题自从有了回文自动机这种东西以后就成为了裸题QAQ
反正就是冲着这个板子来的(感谢黄学长的板子啦啦啦
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define LL long long
#define NN 300005
int n;
char ch[NN];
LL ans = 0ll;
struct Pam
{
int cnt,la,fa[NN],l[NN],size[NN],a[NN][30];
Pam() { cnt = 1, fa[0] = fa[1] = 1, l[1] = -1;}
void extend(int c,int n)
{
int p = la;
while (ch[n-l[p]-1] != ch[n]) p = fa[p];
if (!a[p][c])
{
int now = ++cnt, k = fa[p];
l[now] = l[p] + 2;
while (ch[n-l[k]-1]!=ch[n]) k = fa[k];
fa[now] = a[k][c];
a[p][c] = now;
}
la = a[p][c];
size[la] ++ ;
}
void solve()
{
for (int i=cnt;i;i--)
{
size[fa[i]] += size[i];
ans = max(ans,(LL)size[i] * l[i]);
}
}
}Pam;
int main()
{
scanf("%s",ch+1);
n = strlen(ch+1);
for (int i=1;i<=n;++i) Pam.extend(ch[i]-'a',i);
Pam.solve();
printf("%lld\n",ans);
return 0;
}
2022年8月25日 20:03
Meghalaya Board Model Paper 2023 Class 11 Pdf Download with Answers for Bengali Medium, English Medium, Hindi Medium, Urdu Medium & Students for Small Answers, Long Answer, Very Long Answer Questions, and Essay MBOSE Question Paper Class 11 Type Questions to Term1 & Term2 Exams at official website. New Exam Scheme or Question Pattern for Sammittive Assignment Exams (SA1 & SA2): Very Long Answer (VLA), Long Answer (LA), Small Answer (SA), Very Small Answer (VSA), Single Answer, Multiple Choice and etc.