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/(rl+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[i1][j](1p[i])+f[i1][j1]p[i]

f [ i − 1 ] [ j ] ∗ ( 1 − p [ i ] ) f[i-1][j]*(1-p[i]) f[i1][j](1p[i])是第i个数开头不是1,那么就是前i-1个数里面选,有j个的概率乘上第i个首数字不是1的概率

f [ i − 1 ] [ j − 1 ] ∗ p [ i ] f[i-1][j-1]*p[i] f[i1][j1]p[i]是第i个数字首数字为1的情况,前i-1个数字有j-1个首数字为1的概率乘上第i个数字为1的概率

数位DP:

求区间中首数字等于1的个数需要用到数位DP,否则就会超时。

  1. 首先我们计算位数小于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+...+10cnt1
    对应一位,两位,三位,…,cnt-1位的首数字为1的数字个数,后面的位数都有10种情况,所以乘起来就是乘方
  2. 然后计算位数为cnt的首数字为1的位数
    2.1 如果首数字大于1,那么最高位等于1时后面的数字就可以随便取,因为1小于给出的数的最高位,然后就再加上前面计算的 1 0 c n t − 1 ( t e m p ) 10^{cnt-1}(temp) 10cnt1(temp)就可

    2.2 如果首数字等于1,那么后面就不可以随便取了,能取的数就是 n − 1 0 c n t − 1 ( t e m p ) + 1 n-10^{cnt-1}(temp)+1 n10cnt1(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 #7

Codeforces Beta Round #6 (Div. 2)未完结

Codeforces Beta Round #5

Codeforces Beta Round #3

Codeforces Beta Round #29 (Div. 2, Codeforces format)

Codeforces Beta Round #31 (Div. 2, Codeforces format)