JZOJ4913. 【GDOI2017模拟12.3】告别

Description

定义每一次操作是一个有序的三元组(i,j,k),将序列中的i移到j的位置,j移到k的位置,k移到i的位置。
给定长度为n的序列A[i],求在m次随机操作内将其变为B[i]的期望。
n<=14,m<=1e9

Solution

  • n那么小,m那么大,可以考虑矩乘,但是我们不可能压缩一个n!的状态。
  • 考虑到每一个序列A变成B可以理解成什么,每一个对应数字位置相连之后会变为若干个环,然而环的内的编号对于选取来说实际上是没有用处的
  • 而对于每一个环的特点来说只需要记录它的长度。
  • 那么我们可以发现用环的大小来表示若干种状态可以大大省略状态数。
  • 计算一下我们可以得知,当n=14时环的划分数是135.
  • 既然如此,我们就可以快乐地矩乘了。
  • 转移矩阵:枚举每一种环的划分,任意编号,再暴力每一种三元组,转移成另一种环的划分。
  • 起始:读入的A的对应的环的划分。
  • 终止:一共有n个环的对应位置。
  • 用hash存即可判断编号。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 15
#define maxm 150
#define maxh 1000007
#define mo 998244353
#define ll long long 
using namespace std;

int n,m,i,j,k,a[maxn],b[maxn],p[maxn],to[maxn],q[maxn],bz[maxn],w[maxn];
int hs[maxh],hsx[maxh][maxn],num,T;
ll f[maxm],ff[maxm],g[maxm][maxm],gg[maxm][maxm],inv;

ll ksm(ll x,ll y){
	ll s=1;
	for(;y;y/=2,x=x*x%mo) if (y&1)
		s=s*x%mo;
	return s;
}

int hash(int s,int *a){
	while (hs[s]){
		if (hsx[s][0]==a[0]){
			int i;
			for(i=1;i<=a[0]&&hsx[s][i]==a[i];i++);
			if (i>a[0]) break;
		}
		s=(s+1)%maxh;
	}
	return s;
}

void build(){
	memset(bz,0,sizeof(bz));
	q[0]=0;
	for(int i=1;i<=n;i++) if (!bz[i]){
		int cnt=0;
		for(int x=i;!bz[x];x=to[x]) cnt++,bz[x]=1;
		q[++q[0]]=cnt;
	}
	sort(q+1,q+1+q[0]);
}

void dfs(int i,int low,int tot){
	if (i==n){
		p[0]=tot;
		int s=0; for(int j=1;j<=tot;j++) s=(s*n+p[j])%maxh;
		int X=hash(s,p);
		if (!hs[X]) {
			hs[X]=++num; hsx[X][0]=tot;
			for(int j=1;j<=tot;j++) hsx[X][j]=p[j];
		}
		
		if (tot==n) {g[hs[X]][hs[X]]=1;T=hs[X];return;}
		
		int t=0;
		for(int j=1;j<=tot;j++) {
			for(int k=1;k<=p[j];k++) to[t+k]=t+k%p[j]+1;
			t+=p[j];
		}
		
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) for(int z=1;z<=n;z++) if (x!=y&&x!=z&&y!=z){
			t=to[x]; to[x]=to[y]; to[y]=to[z]; to[z]=t;
			
 			build();
			int ss=0; for(int j=1;j<=q[0];j++) ss=(ss*n+q[j])%maxh;
			int Y=hash(ss,q); 
			if (!hs[Y]) {
				hs[Y]=++num; hsx[Y][0]=q[0];
				for(int j=1;j<=q[0];j++) hsx[Y][j]=q[j];
			}
			(g[hs[X]][hs[Y]]+=inv)%=mo;
			
			t=to[x]; to[x]=to[z]; to[z]=to[y]; to[y]=t;
		}
		return;
	}
	for(int j=low;j<=n-i;j++) {
		p[tot+1]=j;
		dfs(i+j,j,tot+1);
	}
}

int main(){
	freopen("goodbye.in","r",stdin);
	freopen("goodbye.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	for(i=1;i<=n;i++) scanf("%d",&b[i]);
	inv=ksm(n*(n-1)*(n-2),mo-2);
	dfs(0,1,0);
	
	for(i=1;i<=n;i++) w[b[i]]=i;
	for(i=1;i<=n;i++) to[i]=w[a[i]];
	build();
	int s=0; for(i=1;i<=q[0];i++) s=(s*n+q[i])%mo;
	int x=hash(s,q);
	f[hs[x]]=1;
	for(;m;m/=2){
		if (m&1){
			memset(ff,0,sizeof(ff));
			for(i=1;i<=num;i++) for(j=1;j<=num;j++)
				(ff[j]+=f[i]*g[i][j]%mo)%=mo;
			memcpy(f,ff,sizeof(ff));
		}
		memset(gg,0,sizeof(gg));
		for(i=1;i<=num;i++) for(j=1;j<=num;j++) for(k=1;k<=num;k++)
			(gg[i][k]+=g[i][j]*g[j][k]%mo)%=mo;
		memcpy(g,gg,sizeof(gg));
	}
	printf("%lld",f[T]);
}
原文地址:https://www.cnblogs.com/DeepThinking/p/11700944.html