At300 E - Dice Product 3
E.Dice Product 3
题意简述
给定一个初始为 \(1\) 的数,每次掷一个1~6的骰子,在原来的数上乘以骰子上的数,给定一个数 \(n\),掷骰子直到数大于等于 \(n\) 时停止,求最终停止在 \(n\) 的概率,所有数均 取模 \(998244353\)。
解题思路1
概率 dp ,推式子 ,显然有\(f[n]=1/6·(f[n]+f[n/2]+f[n/3]+f[n/4]+f[n/5]+f[n/6])\),
移项,化简,得 \(f[n]=1/5·(f[n/2]+f[n/3]+f[n/4]+f[n/5]+f[n/6])\),注意特判是否整除。这个式子的每一项都可以看作 n 继续递归,直到求出 \(1\) 的时候进行返回。因为递归次数的限制,考虑利用 \(map\) 记忆化处理每一次的结果。
AC code1
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll mod=998244353;
ll q_pow(ll a,ll b){
ll s=1LL;
while(b){
if(b&1){
s=s*a%mod;
}
a=a*a%mod;
b>>=1;
}
return s;
}
ll p;
map<ll,ll>mp;
ll dfs(ll x){
if(x==1) return 1;
if(mp.count(x)) return mp[x];
ll ans=0;
if(x%2==0) ans=(ans+dfs(x/2)*p%mod)%mod;
if(x%3==0) ans=(ans+dfs(x/3)*p%mod)%mod;
if(x%4==0) ans=(ans+dfs(x/4)*p%mod)%mod;
if(x%5==0) ans=(ans+dfs(x/5)*p%mod)%mod;
if(x%6==0) ans=(ans+dfs(x/6)*p%mod)%mod;
return mp[x]=ans;
}
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
ll n;cin>>n;
p=q_pow(5LL,mod-2);
cout<<dfs(n)<<endl;
return 0;
}
解题思路2
本着几乎所有记忆化的搜索都可以改成dp的原则,我们考虑这题的 \(dp\) 形式,发现每次记忆化其实就是对每个因子出现概率做了记录,避免大量重复统计因子的概率。对 n 考虑质因数分解
AC code2
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll mod=998244353;
ll q_pow(ll a,ll b){
ll s=1LL;
while(b){
if(b&1){
s=s*a%mod;
}
a=a*a%mod;
b>>=1;
}
return s;
}
ll f[65][65][65];
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
ll n;cin>>n;
ll p=q_pow(5LL,mod-2);
int _2=0,_3=0,_5=0;
while(n%2==0) n/=2,++_2;
while(n%3==0) n/=3,++_3;
while(n%5==0) n/=5,++_5;
if(n!=1) return cout<<0<<endl,0;
f[0][0][0]=1LL;
for(int i=0;i<=_2;i++){
for(int j=0;j<=_3;j++){
for(int k=0;k<=_5;k++){
(f[i+1][j][k]+=f[i][j][k]*p%mod)%=mod;//2
(f[i][j+1][k]+=f[i][j][k]*p%mod)%=mod;//3
(f[i+2][j][k]+=f[i][j][k]*p%mod)%=mod;//4
(f[i][j][k+1]+=f[i][j][k]*p%mod)%=mod;//5
(f[i+1][j+1][k]+=f[i][j][k]*p%mod)%=mod;//6
}
}
}
cout<<f[_2][_3][_5]<<endl;
return 0;
}