2022牛客暑期多校1_I-Chiitoitsu_概率DP

I-Chiitoitsu_概率DP

题目大意:

初始手牌有 13 张麻将牌,相同牌至多出现 2 张

每轮可以从牌堆摸牌,若达成七对子则自摸胡牌

若不然则选择手牌中某张牌并丢弃之

给定初始手牌,求最优策略下达成七对子的期望轮数

多组数据,数据组数不超过 1e5

思路和代码:

搞懂这个dp推荐读者把dp数组打出来看一下

int n , m , k ; 

ll dp[20][200] ;

inline ll quick_pow(ll a, ll k, ll p) {
	ll res = 1;//快速幂
	a %= p;
	while (k) {
		if (k & 1) res = res * a % p;
		a = a * a % p;
		k >>= 1;
	}
	return res;
}
 
inline ll inv(ll x,ll p){//逆元
	return quick_pow(x,p-2,p);
}

void solve(){

	string s ; cin >> s ;
	n = s.size() ;
	ll cnt = 0 ;
	map<string , int> mp ;
	for(int i = 0 ; i < n ; i += 2)
		mp[s.substr(i , 2)] ++ ;
	
	for(auto x : mp){
		cnt += x.se == 1 ;
	}
//	cout << cnt << " " << m << "\n" ;
	cout << dp[cnt][m] << "\n" ;
	
}//code_by_tyrii 

int main(){
//	freopen("in.in" , "r" , stdin) ;
	ios::sync_with_stdio(false) ;
	cin.tie(0) ; cout.tie(0) ;
	
	m = 9 * 4 * 3 + 7 * 4 - 13 ;//牌堆 
	
	rep(j , 3 , m)
	dp[1][j] = (((j - 3) * (inv(j , mod)) % mod) * dp[1][j - 1] % mod + 1ll) % mod; 

	
	for(int i = 3 ; i <= 13 ; i += 2)
	rep(j , 3 , m){
		ll tmp1 = ((3 * i % mod) * inv(j , mod) % mod) * dp[i - 2][j - 1] % mod ;
		ll tmp2 = (((j - 3 * i + mod) % mod) * inv(j , mod) % mod) * dp[i][j - 1] % mod ;
		dp[i][j] = ((tmp1 + tmp2) % mod + 1LL) % mod ;
	}
	
	ll T ; cin >> T ;
	rep(i , 1 , T){
		cout << "Case #" << i << ": " ;
		solve() ;
	}
	
}
posted @ 2022-07-19 20:45  tyrii  阅读(42)  评论(0)    收藏  举报