【GDOI2017模拟12.3】告别
2016-12-05 19:26
489 查看
Description
给出两个1~n的排列A和B,可以进行m次操作,每次操作随机选择一个三元组(i,j,k),将这个三元组所对应的数在A中进行轮换(即i->j,j->k,k->i)求在m次操作之内将A变成B的概率,答案对998244353取模
n<=14,m<=1e9
Solution
乍一看根本无法下手啊。。。看到n辣么小m辣么大就知道是矩乘可是不会做。。。
如果n再小一点我们可以直接维护状态然后转移,但这样状态太多了
我们考虑怎样压缩状态数。。。
先把B对应成1~n的有序排列,然后我们就只需要对A进行轮换了。。。
一个很好的思路是我们可以用A中的所有置换群来表示A。。。
我们这样只用记录每个置换群的大小就好了,因为只需要本质不同的。。。
B唯一对应n个1,所以不用担心算重。。。
这样设的状态数是n的划分数,n=14时为135
转移的话先枚举状态,随便构造一个满足状态的排列,然后暴力枚举三元组转移,判断转移后的状态是哪一个,这个地方用hash/map/二分之类的就好了
然后把矩阵构造出来直接矩阵乘法就好了
Code
#include <cstdio> #include <cstring> #include <algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) using namespace std; typedef long long ll; const int N=15,M=135,mo=998244353; int a ,c ,w ,h ,x,s,n,m,tot; bool bz ; struct note{ int a ; friend bool operator == (note x,note y) { fo(i,1,n) if (x.a[i]!=y.a[i]) return 0; return 1; } friend bool operator < (note x,note y) { fo(i,1,n) if (x.a[i]<y.a[i]) return 1; else if (x.a[i]>y.a[i]) return 0; return 1; } }q[M],d; struct matrix{ int a[M][M]; friend matrix operator * (matrix y,matrix z) { matrix x;memset(x.a,0,sizeof(x.a)); fo(i,0,tot) fo(j,0,tot) fo(k,0,tot) (x.a[i][j]+=(ll)y.a[i][k]*z.a[k][j]%mo)%=mo; return x; } }g,t; void dfs(int x,int la) { if (x==n) { memcpy(q[tot++].a,d.a,sizeof(d.a)); return; } fo(i,la,n-x) d.a[i]++,dfs(x+i,i),d.a[i]--; } int mi(int x,int y) { int z=1; for(;y;y/=2,x=(ll)x*x%mo) if (y&1) z=(ll)z*x%mo; return z; } note displace(int *a) { memset(bz,0,sizeof(bz)); note A;memset(A.a,0,sizeof(A.a)); fo(i,1,n) if (!bz[i]) { int x=i,size=0; while (!bz[x]) bz[x]=1,x=a[x],size++; A.a[size]++; } return A; } int find(note x) { int l=0,r=tot; while (l<r) { int mid=(l+r)/2; if (q[mid]<x) r=mid; else l=mid+1; } return l; } int main() { freopen("goodbye.in","r",stdin); freopen("goodbye.out","w",stdout); scanf("%d%d",&n,&m);dfs(0,1);tot--; int ni=mi(mi(n*(n-1)*(n-2),m),mo-2); fo(i,1,n) scanf("%d",&a[i]),w[a[i]]=i; fo(i,1,n) { scanf("%d",&x); a[w[x]]=i; } note A=displace(a);g.a[0][0]=n*(n-1)*(n-2); fo(i,0,tot) if (q[i]==A) {s=i;break;} fo(i,1,tot) { memset(c,0,sizeof(c));int len=0; fo(j,1,n) fo(k,1,q[i].a[j]) { fo(l,len+1,len+j-1) c[l]=l+1; c[len+j]=len+1;len+=j; } fo(j,1,n) fo(k,1,n) if (j!=k) fo(l,1,n) if (j!=l&&k!=l) { swap(c[j],c[k]);swap(c[j],c[l]); note C=displace(c); g.a[i][find(C)]++; swap(c[j],c[l]);swap(c[j],c[k]); } } memcpy(t.a,g.a,sizeof(t.a)); for(m--;m;m/=2,g=g*g) if (m&1) t=t*g; printf("%lld\n",(ll)t.a[s][0]*ni%mo); }
相关文章推荐
- 【GDOI2017模拟12.3】告别
- 【JZOJ5324】【GDOI2017模拟8.21】麻将堆
- GDOI2017模拟04.11总结
- 【GDOI2017第二轮模拟day1】公路建设
- 【GDOI2017第三轮模拟day1】影魔(主席树)
- 【GDOI2017第四轮模拟day2】绝版题
- 【GDOI2017模拟10.30】分组
- JZOJ4858. 【GDOI2017模拟11.4】Walk
- 【GDOI2017模拟8.11】生物学家
- GDOI2017模拟第一轮总结
- 【GDOI2017第二轮模拟day1】最长路径
- 【GDOI2017第二轮模拟day1】最长路径(性质题,容斥,组合数学)
- 【GDOI2017模拟9.9】[IOI2007]偶环
- 【GDOI2017第二轮模拟day2】中位数
- JZOJ 4863 【GDOI2017模拟11.5】Market
- 【GDOI2017模拟11.7】太阳神
- JZOJ 4910. 【NOIP2017模拟12.3】子串
- JZOJ 4911 【NOIP2017模拟12.3】人生的叹息
- 【JZOJ4925】【GDOI2017模拟12.18】稻草人
- 【GDOI2017模拟2.14】A