CF54C First Digit Law

题目链接:CF54C. First Digit Law

题意: 给出 [L,R]区间,区间里的每个数出现的概率是1/(R-L+1), 现给出n个区间[Li,Ri ] 现在从每个区间选取一个数,这n个数种至少K%个数前缀为1的概率


这个题目主要是求出区间[ L,R] 里前缀为1的概率,然后概率dp即可


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int inf=0x3fffffff;
const int maxn=1010;

double dp[maxn][maxn];
typedef long long ll;
int digit[20];
ll fac[20];


ll cal(ll n)
{
    int pos=0;
    for(;n;pos++,n/=10) digit[pos]=n%10;
    ll ret=0;
    bool ok=0;
    for(int i=pos-1;i>=0;i--)
    {
      if(digit[i]>=2||ok) ret+=fac[i];
      else if(digit[i]==1){
         ll tmp=1;
         for(int j=0;j<i;j++) tmp+=digit[j]*fac[j];
         ret+=tmp;
      }
      if(digit[i]>=1) ok=1;
    }
    return ret;
}
ll check(ll n)
{
    ll ret=0;
    for(ll i=1;i<=n;i++)
    {
         ll tmp=i,last;
         for(;tmp;tmp/=10) last=tmp%10;
         if(last==1) ret++;
    }
    return ret;
}
int main()
{
    fac[0]=1;
    for(int i=1;i<20;i++) fac[i]=10*fac[i-1];
    int n,K;
    ll L,R;
    while(scanf("%d",&n)==1)
    {
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d %I64d",&L,&R);
            ll num=cal(R)-cal(L-1);
            double p=num*1.0/(R-L+1.0);
            for(int j=i-1;j>=0;j--)
            {
               dp[i][j+1]+=dp[i-1][j]*p;
               dp[i][j]=dp[i-1][j]*(1-p);
            }
        }
        scanf("%d",&K);
        int x=n;
        while(x>=0&&x*100>=n*K) x--;
        x++;
        double ans=0;
        for(int i=x;i<=n;i++) ans+=dp[n][i];
        printf("%.15lf\n",ans);
    }
    return 0;
}


你可能感兴趣的:(CF54C First Digit Law)