hdu 4436 str2int (后缀自动机+dp)
2015-03-11 19:43
453 查看
题意:
给出n个串然后,求着n个串所有子串对应的数字的和是多少。
题解:
根据陈立杰的论文我们得出这样的性质,从s开始遍历自动机,走到任意一个u,那么走过的字符构成的串肯定是整个串的子串,简单来说就是从起点到某个点构成了一个子串。那么我们就可以根据这性质计算。其实我们将串对应的数组分成不同位数进行计算,类似于数位dp的思想。dp[u]表示到节点u时构成的数位对应的数字和,那么u的下个节点v有:dp[v]=(dp[u]*10+cnt[u]*j) cnt是路径数,j是u代表的数字。这样计算其实也就是相当于字典图上的数位dp。好题!但是这样算肯定wa,为什么呢?因为对于这样v可能并不是u实际的“孩子”,因为从后缀动机图可以看出及节点时有跳跃的,那么这样计算不能保证没有后效性的,那么我们可以根据len排序,然后从头开始遍历,这样就解决了这个问题了。
给出n个串然后,求着n个串所有子串对应的数字的和是多少。
题解:
根据陈立杰的论文我们得出这样的性质,从s开始遍历自动机,走到任意一个u,那么走过的字符构成的串肯定是整个串的子串,简单来说就是从起点到某个点构成了一个子串。那么我们就可以根据这性质计算。其实我们将串对应的数组分成不同位数进行计算,类似于数位dp的思想。dp[u]表示到节点u时构成的数位对应的数字和,那么u的下个节点v有:dp[v]=(dp[u]*10+cnt[u]*j) cnt是路径数,j是u代表的数字。这样计算其实也就是相当于字典图上的数位dp。好题!但是这样算肯定wa,为什么呢?因为对于这样v可能并不是u实际的“孩子”,因为从后缀动机图可以看出及节点时有跳跃的,那么这样计算不能保证没有后效性的,那么我们可以根据len排序,然后从头开始遍历,这样就解决了这个问题了。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) void cmax(int& a,int b){ if(b>a)a=b; } void cmin(int& a,int b){ if(b<a)a=b; } typedef long long ll; const int oo=0x3f3f3f3f; const ll OO=1LL<<61; const int MOD=2012; const int maxn=100005; const int maxm=200005; const int SIZE=maxn<<1; const int type=11; int Next[SIZE][type],fa[SIZE],len[SIZE]; int tol,last; char str[maxn]; int dp[SIZE],cnt[SIZE],pos[SIZE]; bool cmp(int a,int b){ return len[a]<len[b]; } struct SuffixAutoMaton{ int newNode(int x){ len[tol]=x; fa[tol]=-1; for(int i=0;i<type;i++) Next[tol][i]=-1; return tol++; } void Init(){ tol=0; last=newNode(0); } void add(int k){ int now=last; int end=newNode(len[now]+1); while(now!=-1&&Next[now][k]==-1){ Next[now][k]=end; now=fa[now]; } if(now==-1) fa[end]=0; else{ int nxt=Next[now][k]; if(len[nxt]==len[now]+1) fa[end]=nxt; else{ int cnxt=newNode(len[now]+1); for(int i=0;i<type;i++)Next[cnxt][i]=Next[nxt][i]; fa[cnxt]=fa[nxt]; fa[nxt]=fa[end]=cnxt; while(now!=-1&&Next[now][k]==nxt){ Next[now][k]=cnxt; now=fa[now]; } } } last=end; } void Insert(char T[]){ for(int i=0;T[i];i++){ add(T[i]-'0'); } } int calc(){ memset(dp,0,sizeof dp); memset(cnt,0,sizeof cnt); for(int i=0;i<tol;i++)pos[i]=i; sort(pos,pos+tol,cmp); cnt[0]=1; for(int i=0;i<tol;i++){ int u=pos[i]; for(int j=0;j<type-1;j++){ if(u==0&&j==0)continue; if(Next[u][j]!=-1){ int v=Next[u][j]; dp[v]=(dp[v]+(dp[u]*10%MOD+cnt[u]*j%MOD)%MOD)%MOD; cnt[v]+=cnt[u]; } } } int ans=0; for(int i=0;i<tol;i++)ans=(ans+dp[i])%MOD; return ans; } }sam; int main(){ int N,ans; while(scanf("%d",&N)!=EOF){ sam.Init(); for(int i=1;i<=N;i++){ scanf("%s",str); sam.Insert(str); sam.add(10); } ans=sam.calc(); printf("%d\n",ans); } return 0; } /** 5 101 123 09 000 1234567890 */
相关文章推荐
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- HDU 4436 str2int【后缀自动机】
- hdu 4436 str2int 后缀数组、后缀自动机
- hdu 4436 str2int(后缀自动机)
- HDU 4436 str2int(后缀自动机)
- HDU 4436 str2int(后缀自动机)
- hdu 4436 str2int(后缀自动机)
- HDU 4436 str2int (后缀自动机)
- HDU 4436 str2int 后缀数组 + 前缀和预处理 或 后缀自动机
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- HDU 4436 str2int(后缀自动机)(2012 Asia Tianjin Regional Contest)
- Hdu 4436 str2int 后缀自动机
- hdu 4436 str2int (后缀自动机)
- HDU 4436(后缀自动机)
- 字符串(多串后缀自动机):HDU 4436 str2int
- 【HDU】5470 Typewriter 【后缀自动机+dp】
- HDU 4436 str2int 后缀数组 字符串哈希 前缀和
- HDU 5343 MZL's Circle Zhou 后缀自动机+DP
- HDU 4436 str2int(后缀数组,一种统计n个digit字符串所有不同子串之和的方法)
- hdu 4436 后缀自动机算和