• 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]);
    }
    
  • 相关阅读:
    图解:在资深架构师眼中的架构应该是怎样的?
    面试必看|面试官之间的“潜规则”
    职业规划:专属程序员的巡礼之年
    互联网企业如何应对网站架构演化带来的“蝴蝶效应”
    阿里首席架构师,是如何选择并落地架构方案的
    你真的了解微服务架构吗?听听八年阿里架构师怎样讲述Dubbo和Spring Cloud微服务架构
    大型分布式电商系统架构演进史?
    大厂面试官:Java工程师的“十项全能”
    打包签名时出现Conversion to Dalvik format failed with error 1
    Android项目混淆打包
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/11700944.html
Copyright © 2020-2023  润新知