給出兩個1~n的排列a和b,可以進行m次操作,每次操作隨機選擇乙個三元組(i,j,k),將這個三元組所對應的數在a中進行輪換(即i->j,j->k,k->i)
求在m次操作之內將a變成b的概率,答案對998244353取模
n<=14,m<=1e9
乍一看根本無法下手啊。。。
看到n辣麼小m辣麼大就知道是矩乘可是不會做。。。
如果n再小一點我們可以直接維護狀態然後轉移,但這樣狀態太多了
我們考慮怎樣壓縮狀態數。。。
先把b對應成1~n的有序排列,然後我們就只需要對a進行輪換了。。。
乙個很好的思路是我們可以用a中的所有置換群來表示a。。。
我們這樣只用記錄每個置換群的大小就好了,因為只需要本質不同的。。。
b唯一對應n個1,所以不用擔心算重。。。
這樣設的狀態數是n的劃分數,n=14時為135
轉移的話先列舉狀態,隨便構造乙個滿足狀態的排列,然後暴力列舉三元組轉移,判斷轉移後的狀態是哪乙個,這個地方用hash/map/二分之類的就好了
然後把矩陣構造出來直接矩陣乘法就好了
#include
#include
#include
#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[n],c[n],w[n],h[n],x,s,n,m,tot;
bool bz[n];
struct note
friend
bool
operator
< (note x,note y)
}q[m],d;
struct matrix
}g,t;
void dfs(int x,int la)
fo(i,la,n-x) d.a[i]++,dfs(x+i,i),d.a[i]--;
}int mi(int x,int y)
note displace(int *a)
return a;
}int find(note x)
return l;
}int main()
note a=displace(a);g.a[0][0]=n*(n-1)*(n-2);
fo(i,0,tot) if (q[i]==a)
fo(i,1,tot)
fo(j,1,n) fo(k,1,n) if (j!=k)
fo(l,1,n) if (j!=l&&k!=l)
}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模擬8 12 躲藏
給出乙個n m的網格圖,圖中有一些障礙節點。現在有a個男生和b個女生,還有乙個小標。男生要和女生配對,小標可以和任何乙個人配對。每一對cp 霧 只能待在乙個點。乙個點只能有一對cp。現在給出a b 1個人的初始座標,和他們的移動速度 即移動到4相鄰格仔所需的時間 所有人同時移動,求完成配對的最小時間...
GDOI2017模擬8 12 新車
平面上有乙個數軸,e點為目標點。你現在要開 車從w前往e,每移動1格需要1l油。你的油箱容量為s,初始時裝滿了98 汽油。數軸上有n個加油站,每個加油站提供98 95 92 中的一種。到了加油站你可以選擇加任意數量的油,你的油箱是茲瓷所有油甚至混合油的。你認為98 最吼,95 其次,92 跑的最慢。...
GDOI2017模擬11 5 總結
看到第一題,哇,數論題,不會啊,感覺要跪 正當我迷茫的時候,突然機房斷電了。啪的一聲大家的電腦都黑了!不知所措!沒辦法,只好等等。過了10分鐘左右,來電了,重新看了看第一題,也許是冷靜下來了,發現直接暴力分解質因數就能過!繼續看第二題,在草稿紙上推了一下,要用揹包,一開始以為會超時,但仔細想了想發現...