您的位置:首页 > 其它

CodeForces 54C-First Digit Law(数位,概率dp)

2015-08-17 22:45 701 查看
题意:

给你n个区间,在每个区间里各取一个数(随机取),求这n个数中超过K%的数是首位为1数的概率

分析:

dp[i][j]取前i个数,有j个是首位为1的数的概率

易知,dp[i][j]=dp[i-1][j]*(1-p[i])+dp[i-1][j-1]*p[i];

现在关键是求p[i],第i个区间首位为1的数出现的概率,用数位统计一下即可

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define read freopen("in.txt", "r", stdin)
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
ll sum[20],a[20];
double dp[1010][1010],p[1010];
int bit[20],n,k;
void init(){
sum[0]=1;
for(int i=1;i<=20;++i)
sum[i]=sum[i-1]*10;
}
ll countsum(int l){
ll total=0;
for(int i=0;i<=l;++i)
total+=sum[i];
return total;
}
//统计首位为1数的数量
ll countone(ll x){
if(x==0)return 0;
init();
int len=0;
while(x){
bit[++len]=x%10;
x/=10;
}
if(bit[len]>1){
return countsum(len-1);
}
else{
ll tmp=countsum(len-2);
a[0]=0;
for(int i=1;i<=len-1;++i)
a[i]=a[i-1]+bit[i]*sum[i-1];
tmp+=a[len-1]+1;
return tmp;
}
}
int main()
{
ll l,r;
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i){
scanf("%I64d%I64d",&l,&r);
ll tmp=countone(r)-countone(l-1);
//cout<<tmp<<endl;
p[i]=1.0*tmp/(r-l+1);
//cout<<p[i]<<endl;
}
dp[1][1]=p[1];
dp[1][0]=1.0-p[1];
for(int i=2;i<=n;++i)
for(int j=0;j<=i;++j){
dp[i][j]+=dp[i-1][j]*(1.0-p[i]);
if(j>0)
dp[i][j]+=dp[i-1][j-1]*p[i];
}
scanf("%d",&k);
double ans=0.0;
for(int j=0;j<=n;++j)
if(j>=(1.0*n*k/100))
ans+=dp
[j];
printf("%.15lf\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: