CodeForces - 452E Three strings
阿新 • • 發佈:2020-12-21
\(\text{Description}\)
\(\text{Solution}\)
容易發現如果算出長度為 \(L\) 的公共字首為 \(x\) 的 \(A,B,C\) 個數為 \((cnt_1,cnt_2,cnt_3)\),那麼長度為 \(len\) 小於 \(L\) 的公共字首為 ”\(x\) 的前 \(len\) 位” 的 \(A,B,C\) 個數至少有 \((cnt_1,cnt_2,cnt_3)\)。
我們將 \(h\) 從大到小列舉,將新的滿足條件的共同前綴合並。
比如有:
\(\text{woshizhu}\)
\(\text{woshixiannv}\)
本來在 \(L>5\)
\(\text{Code}\)
#include <cstdio> #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i) #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i) #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i]) #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i]) #define print(x,y) write(x),putchar(y) template <class T> inline T read(const T sample) { T x=0; int f=1; char s; while((s=getchar())>'9'||s<'0') if(s=='-') f=-1; while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar(); return x*f; } template <class T> inline void write(const T x) { if(x<0) return (void) (putchar('-'),write(-x)); if(x>9) write(x/10); putchar(x%10^48); } template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;} template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;} template <class T> inline T fab(const T x) {return x>0?x:-x;} template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;} template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;} template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;} #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int mod=1e9+7,maxn=3e5+5; int ans[maxn],ret,n,m=122,siz,minn,ori[maxn],op[maxn],x[maxn],y[maxn],sa[maxn],c[maxn],num,rk[maxn],h[maxn],f[maxn],dp[maxn][4],p[maxn]; char s[maxn]; void Read() { scanf("%s",s+1); n=siz=minn=strlen(s+1); rep(i,1,siz) ori[i]=s[i],op[i]=0; ori[++n]=1; op[n]=-1; scanf("%s",s+1); siz=strlen(s+1); minn=Min(minn,siz); rep(i,n+1,n+siz) ori[i]=s[i-n],op[i]=1; ori[n=n+siz+1]=2,op[n]=-1; scanf("%s",s+1); siz=strlen(s+1); minn=Min(minn,siz); rep(i,n+1,n+siz) ori[i]=s[i-n],op[i]=2; n+=siz; } void Suffix() { rep(i,1,n) ++c[x[i]=ori[i]]; rep(i,2,m) c[i]+=c[i-1]; rep(i,1,n) sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1) { num=0; rep(i,n-k+1,n) y[++num]=i; rep(i,1,n) if(sa[i]>k) y[++num]=sa[i]-k; rep(i,1,m) c[i]=0; rep(i,1,n) ++c[x[i]]; rep(i,2,m) c[i]+=c[i-1]; fep(i,n,1) sa[c[x[y[i]]]--]=y[i],y[i]=0; swap(x,y); x[sa[1]]=num=1; rep(i,2,n) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num; m=num; } } void LCP() { int k=0; rep(i,1,n) rk[sa[i]]=i; rep(i,1,n) { if(rk[i]==1) continue; if(k) --k; int j=sa[rk[i]-1]; while(j+k<=n&&i+k<=n&&ori[j+k]==ori[i+k]) ++k; h[rk[i]]=k; } } void init() { rep(i,1,n) f[i]=p[i]=i; } bool cmp(int x,int y) { return h[x]>h[y]; } int Find(int x) {return x==f[x]?x:f[x]=Find(f[x]);} void Merge(int x,int y) { if(x==y) return; ret=(ret-1ll*dp[x][0]*dp[x][1]%mod*dp[x][2]%mod+mod)%mod; // 減去之前的貢獻,不然會算重,因為我們是嚴格要求長度為 L ret=(ret-1ll*dp[y][0]*dp[y][1]%mod*dp[y][2]%mod+mod)%mod; rep(i,0,2) dp[x][i]=(dp[x][i]+dp[y][i])%mod; ret=(ret+1ll*dp[x][0]*dp[x][1]%mod*dp[x][2]%mod+mod)%mod; f[y]=x; } int main() { Read(); Suffix(); LCP(); init(); sort(p+1,p+n+1,cmp); rep(i,1,n) if(~op[i]) dp[i][op[i]]=1; int j=1; fep(i,minn,1) { while(j<=n&&h[p[j]]>=i) { Merge(Find(sa[p[j]]),Find(sa[p[j]-1])); ++j; } ans[i]=ret; } rep(i,1,minn) print(ans[i],' '); puts(""); return 0; }
\(\text{Old Version}\)
感覺題目越來越不會做了怎麼辦\(QWQ\)。如今只有康題解遼。
你能想象這道題用並查集來優化嗎?
列舉特別慢,我們就按順序列舉。從大到小保證符合大的要求一定符合小的要求。
我們相當於做一個字尾和。每次加入新的滿足的情況數。
巧妙的是並查集。因為無法確定下一次,所以只能用一坨的和來做。這就符合並查集的性質。
我的碼風真好看。(自戀五秒鐘)
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int N = 3e5 + 8; const ll mod = 1e9 + 7; int ans[N], f[N], p[N], id[N], lg[N], len, rmq[N][20], n, m, h[N], tax[N], SA[N], tp[N], rk[N], a[N]; ll dp[N][3], tmp; int read() { int x = 0, f = 1; char S; while((S = getchar()) > '9' || S < '0') { if(S == '-') f = -1; if(S == EOF) exit(0); } while(S <= '9' && S >= '0') { x = (x << 1) + (x << 3) + (S ^ 48); S = getchar(); } return x * f; } bool cmp(const int x, const int y, const int d) {return tp[x] == tp[y] && tp[x + d] == tp[y + d];} void Sort() { for(int i = 0; i <= m; ++ i) tax[i] = 0; for(int i = 1; i <= n; ++ i) ++ tax[rk[tp[i]]]; for(int i = 1; i <= m; ++ i) tax[i] += tax[i - 1]; for(int i = n; i >= 1; -- i) SA[tax[rk[tp[i]]] --] = tp[i]; } void init() { char ch[N]; scanf("%s", ch); int siz = strlen(ch); len = siz; for(int i = 0; i < siz; ++ i) a[++ n] = ch[i], id[n] = 1; a[++ n] = 1; id[n] = -1; scanf("%s", ch); siz = strlen(ch); len = min(len, siz); for(int i = 0; i < siz; ++ i) a[++ n] = ch[i], id[n] = 2; a[++ n] = 2; id[n] = -1; scanf("%s", ch); siz = strlen(ch); len = min(len, siz); for(int i = 0; i < siz; ++ i) a[++ n] = ch[i], id[n] = 3; a[++ n] = 3; id[n] = -1; m = 122; } void Suffix() { init(); for(int i = 1; i <= n; ++ i) rk[i] = a[i], tp[i] = i; Sort(); for(int w = 1, p = 1, i; p < n; m = p, w <<= 1) { for(p = 0, i = n - w + 1; i <= n; ++ i) tp[++ p] = i; for(i = 1; i <= n; ++ i) if(SA[i] > w) tp[++ p] = SA[i] - w; Sort(); swap(rk, tp); rk[SA[1]] = p = 1; for(i = 2; i <= n; ++ i) rk[SA[i]] = cmp(SA[i], SA[i - 1], w) ? p : ++ p; } int j, k = 0; for(int i = 1; i <= n; h[rk[i ++]] = k) for(k = k ? k - 1 : k, j = SA[rk[i] - 1]; a[i + k] == a[j + k]; ++ k); for(int i = 2; i <= n; ++ i) lg[i] = lg[i >> 1] + 1; for(int i = 1; i <= n; ++ i) rmq[i][0] = h[i]; for(int j = 1; (1 << j) <= n; ++ j) for(int i = 1; i + (1 << j) - 1 <= n; ++ i) rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << j - 1)][j - 1]); } int lcp(const int x, const int y) { int l = rk[x], r = rk[y]; if(l == r) return n - SA[l] + 1; if(l > r) swap(l, r); int t = lg[r - l]; return min(rmq[l + 1][t], rmq[r - (1 << t) + 1][t]); } void makeSet() { for(int i = 1; i <= n; ++ i) p[i] = i, f[i] = i; } int findSet(const int x) { return x == f[x] ? x : f[x] = findSet(f[x]); } void sub(ll &x, const int y) { x = (x - y + mod) % mod; } void unionSet(const int x, const int y) { sub(tmp, dp[x][0] * dp[x][1] % mod * dp[x][2] % mod); sub(tmp, dp[y][0] * dp[y][1] % mod * dp[y][2] % mod); for(int i = 0; i < 3; ++ i) (dp[x][i] += dp[y][i]) %= mod; (tmp += dp[x][0] * dp[x][1] % mod * dp[x][2] % mod) %= mod; f[y] = x; } bool Cmp(const int x, const int y) { return h[x] > h[y]; } int main() { Suffix(); makeSet(); sort(p + 1, p + n + 1, Cmp); for(int i = 1; i <= n; ++ i) if(id[i] >= 1) dp[i][id[i] - 1] = 1; int j = 1; for(int i = len; i >= 1; -- i) { while(j <= n && h[p[j]] >= i) { unionSet(findSet(SA[p[j] - 1]), findSet(SA[p[j]])); ++ j; } ans[i] = tmp; } for(int i = 1; i <= len; ++ i) printf("%d ", ans[i]); putchar('\n'); return 0; }