题目链接: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; }