1. 程式人生 > 實用技巧 >AGC 050 D題解

AGC 050 D題解

AGC 050 D題解

比賽的時候想到了O(N^6)的做法沒敢寫

這題的資料範圍非常迷惑,如果你O(N^6)的做法,請關閉這篇題解,自己嘗試寫出來,然後就可以AC了

4e9的運算量只跑了 780ms,是真的神奇

首先這題的dp樣子比較顯然(一眼dp題)

可以先預處理處一個數組\(p_{i,j,k,l}\)表示當前是第j輪,有i個人玩這個遊戲,在這之前已經有k個人勝利了,最後這i個人當中又有l個勝利的概率。

這個東西的轉移比較簡單,隨便暴力轉移也不會T。

然後後面的步驟更加簡單,每一個人分開來計算。

\(dp_{i,l,r}\)表示當前到達這個欽定的人,前面還剩下l個,後面還剩下r個人,到達這部的概率的概率。

轉移直接列舉上一維的\(l',r'\)就行了。

所以這題的區分度主要在於你是否敢寫

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MOD=998244353;
LL quick(LL A,LL B){
	if(B==0) return 1;
	LL  tmp=quick(A,B>>1);
	tmp*=tmp;
	tmp%=MOD;
	if(B&1)
		tmp*=A,tmp%=MOD;
 	return tmp;
}
int invm;
int n,m;
int p[43][43][43][43];
int dp[43][43][43];
int good[43][43][43];
/* 
dp[i][j][l][m]=p[i-1][j][l]*p[n-i][j-1][m]
*/ 
int main(){
	scanf("%d%d",&n,&m);
	invm=quick(m,MOD-2);
	rb(i,0,n) p[i][0][0][0]=1;
	rb(i,1,m+1) rb(j,i-1,m+1) p[0][i][j][0]=1;
	rb(i,1,n){
		rb(j,1,m+1){//now 
			rb(k,j-1,m+1){
				rb(l,0,i){
					if(l&&(m-(j-1))>=(m-k-(l-1))){
						p[i][j][k][l]+=1ll*p[i-1][j][k][l-1]*(m-k-(l-1))%MOD*quick(m-(j-1),MOD-2)%MOD;
					}
					if(m-(j-1)>=(k+l-(j-1))){
						p[i][j][k][l]+=1ll*p[i-1][j][k][l]*(k+l-(j-1))%MOD*quick(m-(j-1),MOD-2)%MOD;
					}
					p[i][j][k][l]%=MOD; 
				}
			}
		}
	}
	rb(now,1,n){
		memset(good,0,sizeof(good));
		memset(dp,0,sizeof(dp));
		int rest=0;
		dp[0][now-1][n-now]=1;
		rb(i,1,m){
			rb(l,0,now-1){
				rb(r,0,n-now){
					rb(j,0,(now-1)-l){
						rb(k,0,(n-now)-r){
							dp[i][l][r]+=1ll*dp[i-1][l+j][r+k]*(1-good[i-1][l+j][r+k]+MOD)%MOD*p[r+k][i-1][(n-1-(l+j)-(r+k))][k]%MOD*p[l+j][i][n-1-(l+j)-r][j]%MOD;
							dp[i][l][r]%=MOD;
						}
					}
					int res=m-(n-1-l-r);
					good[i][l][r]=res*quick(m-(i-1),MOD-2)%MOD;
					rest+=1ll*dp[i][l][r]*good[i][l][r]%MOD;
					rest%=MOD;
				} 
			} 
		}
		printf("%d\n",rest);
	} 
	return 0;
}

/*

4 2
1
374341633
748683265
873463809

*/