告别
来源:互联网 发布:英国博士 知乎 编辑:程序博客网 时间:2024/04/28 19:30
题目大意
一个n的排列,每次可以选择三个不同位置(这三个位置有序,(2,1,3)与(1,2,3)不同),然后对它们进行一次轮换。
只能操作m次,某一次操作过后当前排列变成了目标排列则停止操作。
每次均等概率选择三个有序位置进行操作。
在模意义下求m次操作内变成目标排列的概率。
设状态
首先可以扭转初始排列和目标排列,使得目标排列变成有序的(就是变成1,2,3……n)
我们知道可以用置换来表示一个排列,目标排列此时对应n个单位置换,同时n个单位置换也一定只对应目标排列。
对于两种置换,如果其中所有置换长度组成的多重集合完全相同,能拓展出的状态也完全相同,因此应该考虑缩到一起。
这样子状态只有135种。
暴力枚举每种状态,然后可以构造出与其对应的一个可行排列,再暴力枚举三个有序位置,然后再找会变成哪个状态(可以二分或map)
由于走到目标状态就停止操作,因此目标状态不能有连向其他状态的边,只能有一个自环(方便我们得到m次以内而不是恰好m次)
得到转移矩阵后可以做矩阵乘法。
#include<cstdio>#include<algorithm>#include<map>#include<vector>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=150+10,mo=998244353;typedef long long ll;vector<int> now;map<vector<int>,int> ha;int c[maxn][20];int dis[maxn][maxn],ans[maxn][maxn],o[maxn][maxn],sta[60],a[20],b[20],d[20],ts[20],p[20];bool bz[20];int i,j,k,l,t,n,m,sid,tid,tot,top,sum,cnt,w1,w2,w3,num;int quicksortmi(int x,int y){ if (!y) return 1; int t=quicksortmi(x,y/2); t=(ll)t*t%mo; if (y%2) t=(ll)t*x%mo; return t;}void dfs(int x,int dow,int y){ if (!y){ int i; top++; fo(i,1,x-1) c[top][i]=p[i]; c[top][0]=x-1; now.clear(); fo(i,1,x-1) now.push_back(p[i]); ha[now]=top; return; } int i; fo(i,dow,y){ p[x]=i; dfs(x+1,i,y-i); }}int getid(){ int i; now.clear(); fo(i,1,cnt) now.push_back(d[i]); return ha[now];}int change(int x,int y,int z){ int i; fo(i,1,n) b[i]=a[i]; int t=b[x]; b[x]=b[y]; b[y]=b[z]; b[z]=t; cnt=0; fo(i,1,n) bz[i]=0; fo(i,1,n) if (!bz[i]){ t=0; j=i; while (!bz[j]){ bz[j]=1; t++; j=b[j]; } d[++cnt]=t; } sort(d+1,d+cnt+1); return getid();}int main(){ freopen("goodbye.in","r",stdin);freopen("goodbye.out","w",stdout); scanf("%d%d",&n,&m); num=quicksortmi(n*(n-1)*(n-2),m); num=quicksortmi(num,mo-2); fo(i,1,n) scanf("%d",&a[i]); fo(i,1,n) scanf("%d",&b[i]); fo(i,1,n) ts[b[i]]=i; fo(i,1,n) a[i]=ts[a[i]],b[i]=i; dfs(1,1,n); fo(i,1,n) if (!bz[i]){ t=0; j=i; while (!bz[j]){ bz[j]=1; t++; j=a[j]; } d[++cnt]=t; } sort(d+1,d+cnt+1); sid=getid(); fo(i,1,n) d[i]=1; cnt=n; tid=getid(); fo(i,1,top){ j=1;k=1; while (j<=c[i][0]){ fo(l,k,k+c[i][j]-2) a[l]=l+1; a[k+c[i][j]-1]=k; k+=c[i][j]; j++; } fo(w1,1,n) fo(w2,1,n) fo(w3,1,n) if (w1!=w2&&w1!=w3&&w2!=w3){ j=change(w1,w2,w3); if (i==1) j=1; (dis[i][j]+=1)%=mo; } } //dis[tid][n+1]=dis[n+1][n+1]=1; /*fo(i,1,n){ fo(j,1,n) printf("%d ",dis[i][j]); printf("\n"); }*/ //m++; while (m){ sta[++sum]=m%2; m/=2; } fo(i,1,top) ans[i][i]=1; while (sum){ fo(i,1,top) fo(j,1,top) o[i][j]=0; fo(k,1,top) fo(i,1,top) fo(j,1,top) o[i][j]=(o[i][j]+(ll)ans[i][k]*ans[k][j]%mo)%mo; fo(i,1,top) fo(j,1,top) ans[i][j]=o[i][j]; if (sta[sum]){ fo(i,1,top) fo(j,1,top) o[i][j]=0; fo(k,1,top) fo(i,1,top) fo(j,1,top) o[i][j]=(o[i][j]+(ll)ans[i][k]*dis[k][j]%mo)%mo; fo(i,1,top) fo(j,1,top) ans[i][j]=o[i][j]; } sum--; } /*fo(i,1,n){ fo(j,1,n) printf("%d ",ans[i][j]); printf("\n"); }*/ fo(i,1,top) fo(j,1,top) dis[i][j]=0; dis[1][sid]=1; fo(i,1,top) fo(j,1,top) o[i][j]=0; fo(k,1,top) fo(i,1,top) fo(j,1,top) o[i][j]=(o[i][j]+(ll)dis[i][k]*ans[k][j]%mo)%mo; fo(i,1,top) fo(j,1,top) ans[i][j]=o[i][j]; printf("%d\n",(ll)ans[1][1]*num%mo);}
0 0
- 告别
- 告别
- 告别
- 告别
- 告别
- 告别
- 告别阿根廷,告别世界杯
- 告别浮华
- 告别篇
- 告别Flashget
- 告别无聊
- 告别昨天
- 告别ACM
- 告别微星
- 告别程序员
- 告别WOW
- 告别九月
- 告别失败
- Spring3 MVC入门实例(示例)Spring3 MVC教程
- 设计模式学习13——代理模式
- Spark-Streaming获取kafka数据的两种方式-Receiver与Direct的方式
- C++ 为什么不加入垃圾回收机制
- ffmpeg错误打印Invalid UE golomb code的解决
- 告别
- 协同过滤(ALS)算法原理及Spark MLlib调用实例(Scala/Java/Python)
- NSLog 输出格式
- LeakCanary常用插件:检测所有的内存泄漏
- 数据挖掘和机器学习的策略
- opencv中copyTo函数的使用
- Material Design Button的使用方法以及默认间距问题的适配
- ORA-01078和ORA-00109的解决方法
- mac使用Dryrun做到不用运行Android Studio即可在模拟器安装预览GitHub开源项目