CCPC2020長春 G題 Monkey's Keyboard
阿新 • • 發佈:2020-12-08
連結:
https://codeforces.com/gym/102832/problem/G
Pro:
給定一個
Sol:
很容易想到另一個題,叫歌唱王國。
然後按照那道題的套路推一發式子
發現對於任意一個字串的
\[\begin{align*} ans_S&=\sum_{i,i\ is\ a\ border\ of\ S} \prod_{j=1}^i \frac{1}{p_i} \\ &=\sum_{i,i\ is\ a\ border\ of\ S} w_i (寫成一個字首積的形式) \end{align*} \]發現這個式子的貢獻
只和border有關
然後總答案的話可以考慮列舉border是誰
然後算這個border的貢獻是多少
具體地說
首先,列舉border顯然可以用SAM來實現
然後考慮貢獻怎麼計算
簡單推到即可發現
對於SAM上任意一個節點\(x\)
其貢獻為 \[\begin{align*} ans&=\sum_{len=a}^b\sum_{r=1}^{cnt[x]} \sum_{l=1}^r \frac{w_{pos}}{w_{pos-len}} \\ &=\frac{cnt_x*(cnt_x+1)}{2}*\sum_{len=a}^b\frac{w_{pos}}{w_{pos-len}} \\ &=\frac{cnt_x*(cnt_x+1)}{2}*{w_{pos}}*\sum_{len=a}^b\frac{1}{w_{pos-len}} \end{align*} \]
對於w陣列的倒數搞一個字首和即可
#include<bits/stdc++.h> #define N 1100000 #define db double #define ll long long #define ldb long double #define ull unsigned long long using namespace std; const int h=3,ki=149,mo=1e9+7; int mod(int x){return (x%mo+mo)%mo;} int inc(int x,int k){x+=k;return x<mo?x:x-mo;} int dec(int x,int k){x-=k;return x>=0?x:x+mo;} int ksm(int x,int k) { int ans=1; while(k){if(k&1)ans=1ll*ans*x%mo;k>>=1;x=1ll*x*x%mo;} return mod(ans); } int inv(int x){return ksm(x,mo-2);} int read() { char ch=0;int x=0,flag=1; while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();} return x*flag; } void write(int x) { if(!x)return (void)putchar(48); if(x<0)putchar(45),x=-x; int len=0,p[20]; while(x)p[++len]=x%10,x/=10; for(int i=len;i>=1;i--)putchar(p[i]+48); } const db eps=1e-7,inf=1e9+7,pi=acos(-1); db Read(){db x;scanf("%lf",&x);return x;} void Write(db x){printf("%lf",x);} char ch[N]; int root=1,size=1,last=1,sz[N]; struct node{int pos,len,lnk,nxt[26];}s[N]; void insert(int k) { int cur=++size,p=last;last=cur; sz[cur]=1;s[cur].pos=s[cur].len=s[p].len+1; while(p&&!s[p].nxt[k])s[p].nxt[k]=cur,p=s[p].lnk; if(!p){s[cur].lnk=root;return;} int q=s[p].nxt[k]; if(s[p].len+1==s[q].len)s[cur].lnk=q; else { int clone=++size; s[clone]=s[q];s[clone].len=s[p].len+1; while(p&&s[p].nxt[k]==q)s[p].nxt[k]=clone,p=s[p].lnk; s[q].lnk=s[cur].lnk=clone; } } struct edge{int to,nxt;}e[N]; int num,head[N]; void add(int x,int y){e[++num]={y,head[x]};head[x]=num;} void dfs(int x,int fa) { for(int i=head[x];i!=-1;i=e[i].nxt) { int to=e[i].to; if(to==fa)continue; dfs(to,x);sz[x]+=sz[to]; } } int p[N],w[N],v[N]; int main() { scanf("%s",ch+1); int n=strlen(ch+1),tot=0,ans=0; for(int i=1;i<=n;i++)insert(ch[i]-'a'); for(int i=0;i<26;i++)p[i]=read(),tot=inc(tot,p[i]); for(int i=0;i<26;i++)p[i]=1ll*tot*inv(p[i])%mo; w[0]=1;for(int i=1;i<=n;i++)w[i]=1ll*w[i-1]*p[ch[i]-'a']%mo; v[0]=1;for(int i=1;i<=n;i++)v[i]=inc(v[i-1],inv(w[i])); num=-1;memset(head,-1,sizeof(head)); for(int x=2;x<=size;x++)add(s[x].lnk,x);dfs(1,1); for(int x=2;x<=size;x++) { int a=s[s[x].lnk].len+1,b=s[x].len; int l=s[x].pos-b,r=s[x].pos-a; int t=1ll*(sz[x]+1)*sz[x]%mo*inv(2)%mo*w[s[x].pos]%mo; if(r>=0)ans=inc(ans,1ll*t*v[r]%mo); if(l-1>=0)ans=dec(ans,1ll*t*v[l-1]%mo); } write(ans); return 0; }