Codeforces Beta Round #50 C 数位DP+概率DP
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Beta Round #50 C 数位DP+概率DP相关的知识,希望对你有一定的参考价值。
C. First Digit Law
题意:
有n
个区间,每个区间代表一个数,这个数取值的范围就是这个区间代表的范围。
然后问这n
个数中代表的数首数字为1
的占的比率大于等于 K % K \\% K%的概率
思路:
题目有点绕。
我们可以先求n
个数中首数字为1
的概率,然后与K%
比较,如果大于等于K%
的话就让结果把这个概率加上。
概率DP
首先我们要求出来每个区间首数字为1的概率,就是首数字为1的数字个数除于区间中的数的总个数,对应 p [ i ] = ( d o u b l e ) c n t / ( r − l + 1 ) p[i] = (double)cnt/(r-l+1) p[i]=(double)cnt/(r−l+1)
状态表示:
f [ i ] [ j ] f[i][j] f[i][j]为前i
个数中有j
个数满足第一位为1
的概率
转移方程:
f [ i ] [ j ] = f [ i − 1 ] [ j ] ∗ ( 1 − p [ i ] ) + f [ i − 1 ] [ j − 1 ] ∗ p [ i ] f[i][j] = f[i-1][j]*(1-p[i]) + f[i-1][j-1]*p[i] f[i][j]=f[i−1][j]∗(1−p[i])+f[i−1][j−1]∗p[i]
f [ i − 1 ] [ j ] ∗ ( 1 − p [ i ] ) f[i-1][j]*(1-p[i]) f[i−1][j]∗(1−p[i])是第i个数开头不是1
,那么就是前i-1
个数里面选,有j
个的概率乘上第i
个首数字不是1
的概率
f [ i − 1 ] [ j − 1 ] ∗ p [ i ] f[i-1][j-1]*p[i] f[i−1][j−1]∗p[i]是第i
个数字首数字为1
的情况,前i-1
个数字有j-1
个首数字为1
的概率乘上第i
个数字为1
的概率
数位DP:
求区间中首数字等于1的个数需要用到数位DP,否则就会超时。
- 首先我们计算位数小于cnt的首数字为1的个数(
cnt
为总位数)
1 + 1 0 1 + 1 0 2 + . . . + 1 0 c n t − 1 1+10^1+10^2+...+10^{cnt-1} 1+101+102+...+10cnt−1
对应一位,两位,三位,…,cnt-1
位的首数字为1
的数字个数,后面的位数都有10种情况,所以乘起来就是乘方- 然后计算位数为
cnt
的首数字为1
的位数
2.1 如果首数字大于1
,那么最高位等于1
时后面的数字就可以随便取,因为1
小于给出的数的最高位,然后就再加上前面计算的 1 0 c n t − 1 ( t e m p ) 10^{cnt-1}(temp) 10cnt−1(temp)就可
2.2 如果首数字等于1
,那么后面就不可以随便取了,能取的数就是 n − 1 0 c n t − 1 ( t e m p ) + 1 n-10^{cnt-1}(temp)+1 n−10cnt−1(temp)+1种了
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 1e5+5,M = 2e5+5;
int n,m,k;
double p[1005],f[1005][1005];
ll dp(ll n)
{
if(!n) return 0;
ll t = n;
vector<int>nums;
while(n) nums.emplace_back(n%10),n/=10;
ll ans = 0;
ll temp = 1;
for(int i=1;i<=nums.size()-1;i++,temp *= 10) ans += temp;
if(nums.back()>1) return ans+temp;
else return ans+t-temp+1;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
ll l,r;
ll cnt = 0;
cin>>l>>r;
cnt = dp(r)-dp(l-1);
p[i] = (double)cnt/(r-l+1);
}
cin>>k;
f[0][0] = 1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0) f[i][j] = f[i-1][j]*(1-p[i]);
else f[i][j] = f[i-1][j]*(1-p[i]) + f[i-1][j-1]*p[i];
}
}
double res = 0;
for(int i=0;i<=n;i++)
{
double x = 100.0*i/n;
if(x>=k) res += f[n][i];
}
printf("%.15lf\\n",res);
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0),cout.tie(0);
int _;
// cin>>_;
_ = 1;
while(_--)
{
solve();
}
return 0;
}
以上是关于Codeforces Beta Round #50 C 数位DP+概率DP的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Beta Round #6 (Div. 2)未完结