这里会显示出您选择的修订版和当前版本之间的差别。
| 后一修订版 | 前一修订版 | ||
|
2020-2021:teams:die_java:front_page_summertrain13 [2020/08/21 16:43] mychael 创建 |
2020-2021:teams:die_java:front_page_summertrain13 [2020/08/21 17:07] (当前版本) wxg [训练总结] |
||
|---|---|---|---|
| 行 14: | 行 14: | ||
| === 题意 === | === 题意 === | ||
| + | 给了一个字符串,问你有多少子串,自身是回文串而且一半也是回文串 | ||
| === 题解 === | === 题解 === | ||
| + | 由回文自动机的性质知道一个串的本质不同的回文串最多有 $n$ 个,我们可以用回文自动机统计不同回文串的个数并标记位置,之后枚举每个串并用哈希判断他的一半是不是回文串就行 | ||
| <hidden 代码><code cpp> | <hidden 代码><code cpp> | ||
| + | #include<iostream> | ||
| + | #include<cstdio> | ||
| + | #include<algorithm> | ||
| + | #include<cstring> | ||
| + | #define ll long long | ||
| + | using namespace std; | ||
| + | const int N=300055; | ||
| + | char s[N]; | ||
| + | int fail[N],len[N],last,n,tot,ch[N][26],cnt[N],ps[N],ans[N]; | ||
| + | ll hs[N],pw[N],hs2[N]; | ||
| + | int newnode(int x) | ||
| + | { | ||
| + | len[++tot]=x;return tot; | ||
| + | } | ||
| + | void init() | ||
| + | { | ||
| + | tot=-1;last=0; | ||
| + | newnode(0);newnode(-1); | ||
| + | fail[0]=1;s[0]=-1; | ||
| + | } | ||
| + | |||
| + | int getfail(int pos,int x) | ||
| + | { | ||
| + | while(s[pos-len[x]-1]!=s[pos]) x=fail[x]; | ||
| + | return x; | ||
| + | } | ||
| + | |||
| + | void add(int x,int c) | ||
| + | { | ||
| + | int cur=getfail(x,last); | ||
| + | if(!ch[cur][c]) | ||
| + | { | ||
| + | int now=newnode(len[cur]+2); | ||
| + | fail[now]=ch[getfail(x,fail[cur])][c]; | ||
| + | ch[cur][c]=now; | ||
| + | } | ||
| + | cnt[last=ch[cur][c]]++;ps[last]=x; | ||
| + | } | ||
| + | ll query(int l,int r,int opt) | ||
| + | { | ||
| + | int len=r-l+1; | ||
| + | if(opt==1) | ||
| + | { | ||
| + | return hs[r]-hs[l-1]*pw[len]; | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | return hs2[l]-hs2[r+1]*pw[len]; | ||
| + | } | ||
| + | } | ||
| + | int chk(int l,int r) | ||
| + | { | ||
| + | int mid=l+r>>1,len=r-l+1; | ||
| + | if(len&1) | ||
| + | { | ||
| + | return query(l,mid,1)==query(mid,r,2); | ||
| + | } | ||
| + | else return query(l,mid,1)==query(mid+1,r,2); | ||
| + | } | ||
| + | int main() | ||
| + | { | ||
| + | pw[0]=1; | ||
| + | for(int i=1;i<N;i++) | ||
| + | pw[i]=pw[i-1]*31; | ||
| + | while(scanf("%s",s+1)!=EOF) | ||
| + | { | ||
| + | n=strlen(s+1);init(); | ||
| + | for(int i=1;i<=n;i++) | ||
| + | { | ||
| + | add(i,s[i]-'a');//if(i<=3) cout<<last<<endl; | ||
| + | hs[i]=hs[i-1]*31+(s[i]-'a'+1); | ||
| + | } | ||
| + | hs2[n+1]=0; | ||
| + | for(int i=n;i;i--) | ||
| + | hs2[i]=hs2[i+1]*31+(s[i]-'a'+1); | ||
| + | for(int i=tot;i>1;i--) | ||
| + | { | ||
| + | // cout<<len[i]<<" "<<cnt[i]<<" "<<ps[i]<<endl; | ||
| + | cnt[fail[i]]+=cnt[i]; | ||
| + | if(chk(ps[i]-len[i]+1,ps[i]-len[i]+(len[i]+1)/2)) | ||
| + | ans[len[i]]+=cnt[i]; | ||
| + | } | ||
| + | printf("%d",ans[1]);ans[1]=0; | ||
| + | for(int i=0;i<=tot;i++) | ||
| + | len[i]=fail[i]=cnt[i]=ps[i]=0,memset(ch[i],0,sizeof(ch[i])); | ||
| + | for(int i=2;i<=n;i++) | ||
| + | printf(" %d",ans[i]),ans[i]=0; | ||
| + | puts(""); | ||
| + | } | ||
| + | return 0; | ||
| + | } | ||
| </code></hidden> | </code></hidden> | ||
| ===== J.Just Skip The Problem ===== | ===== J.Just Skip The Problem ===== | ||
| 行 27: | 行 119: | ||
| === 题意 === | === 题意 === | ||
| + | 求 $n$ 的阶乘,水 | ||
| - | === 题解 === | ||
| - | |||
| - | |||
| - | <hidden 代码><code cpp> | ||
| - | |||
| - | </code></hidden> | ||
| ===== K.Keen On Everything But Triangle ===== | ===== K.Keen On Everything But Triangle ===== | ||
| 行 221: | 行 308: | ||
| ===== 训练总结 ===== | ===== 训练总结 ===== | ||
| - | wxg: | + | wxg: 网络流没有想出来模型,以后要多练练 |
| hxm:比较遗憾B最后差一点没写出 | hxm:比较遗憾B最后差一点没写出 | ||