您的位置:首页 > 其它

告别

2016-12-06 17:03 134 查看

题目大意

一个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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: