#弦图,并查集,扩展KMP#洛谷 15549 「Stoi2037」不能说的秘密
分析
由于存在 \(p_i=m\),那么 \(S[i,i+m-1]=T[1,m],z_j=\min\{p_{i+j-1},m-i+1\}\)。
然后根据扩展 KMP 可以发现 \(S[i],T[j]\) 以及 \(T[i],T[j]\) 存在相等或不等的关系,用并查集合并相等关系后,
剩下相当于 \(c-\)染色,而构造出来的图其实是弦图,弦图染色方案数是 \(\prod (c-label[x])\),跑 MCS 求出 label 即可。
特别地,如果不存在 \(p_i=m\),那么 \(T_{\max\{p_i\}+1}\) 也存在不等关系,
此时图不一定是弦图,虽然后缀能任选,但也许得在弦图的消除序列上dp。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N=2000011; struct node{int y,next;}e[N<<3]; vector<int>K[N]; pair<int,int>b[N];
int T,n,m,k,et,as[N],label[N],peo[N],v[N],tag[N],p[N],z[N],f[N],flag,ans,tot;
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
void Get_Z(int m){
z[1]=m;
for (int i=2,l=0,r=0;i<=m;++i){
int now=0;
if (i<=r){
if (z[i-l+1]<r-i+1){
if (z[i]!=z[i-l+1]){
flag=0;
continue;
}
now=z[i];
}else{
if (z[i]<r-i+1){
flag=0;
continue;
}
now=r-i+1;
}
}
for (int j=now;j<z[i];++j){
int fa=getf(n+j+i),fb=getf(n+j+1);
if (fa>fb) swap(fa,fb);
if (fa!=fb) f[fa]=fb;
}
if (i+z[i]-1>r) l=i,r=i+z[i]-1;
if (i+z[i]<=m) b[++tot]=make_pair(n+z[i]+i,n+z[i]+1);
}
}
void ExKMP(int n){
for (int i=1,l=0,r=0;i<=n;++i){
int now=0;
if (i<=r){
if (z[i-l+1]<r-i+1){
if (p[i]!=z[i-l+1]){
flag=0;
continue;
}
now=p[i];
}else{
if (p[i]<r-i+1){
flag=0;
continue;
}
now=r-i+1;
}
}
for (int j=now;j<p[i];++j){
int fa=getf(j+i),fb=getf(n+j+1);
if (fa>fb) swap(fa,fb);
if (fa!=fb) f[fa]=fb;
}
if (i+p[i]-1>r) l=i,r=i+p[i]-1;
if (i+p[i]<=n&&p[i]<m) b[++tot]=make_pair(p[i]+i,n+p[i]+1);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for (cin>>T;T;--T){
cin>>n>>m>>k,et=flag=ans=1,tot=0;
for (int i=1;i<=n;++i){
cin>>p[i];
if (i+p[i]-1>n) flag=0;
if (p[i]==m) flag=i;
}
if (!flag){
cout<<0<<'\n';
continue;
}
for (int i=1;i<=m;++i) z[i]=min(p[flag+i-1],m-i+1);
for (int i=0;i<=n+m;++i) f[i]=i;
flag=1,Get_Z(m),ExKMP(n);
for (int i=1;i<=tot;++i){
int x=getf(b[i].first),y=getf(b[i].second);
if (x==y){
flag=0;
break;
}
}
if (!flag){
cout<<0<<'\n';
continue;
}
for (int i=1;i<=tot;++i){
int x=getf(b[i].first),y=getf(b[i].second);
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
tot=0;
for (int i=1;i<=n+m;++i)
if (getf(i)==i) K[0].push_back(i),++tot;
for (int i=tot,mx=0;i;--i){
int x=-1;
while (x==-1){
while (K[mx].empty()) --mx;
x=K[mx].back(),K[mx].pop_back();
if (v[x]||label[x]!=mx) {x=-1; continue;}
}
v[x]=1,peo[i]=x;
if (label[x]>=k) ans=0;
else ans=1ll*ans*(k-label[x])%173127047;
for (int j=as[x];j;j=e[j].next)
if (!v[e[j].y]&&tag[e[j].y]!=x){
tag[e[j].y]=x;
if (++label[e[j].y]>mx) mx=label[e[j].y];
K[label[e[j].y]].push_back(e[j].y);
}
}
cout<<ans<<'\n';
for (int i=0;i<=n+m;++i) as[i]=label[i]=tag[i]=peo[i]=v[i]=0,K[i].clear();
}
return 0;
}

浙公网安备 33010602011771号