Codeforces 45C

本文解析了一道关于概率动态规划的问题,详细介绍了实现过程中的五个常见陷阱,并提供了完整的代码示例。涉及统计数字位数、避免数据类型导致的错误等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一道比较好的题,虽然不难,不过该考察的细节都考察了,不容易ac
很显然的概率dp dp[i][j] 表示前i个区间,选取了j个区间有首位为1的概率,然后答案就是求和。
坑点1:统计数位的时候,细节很多稍不注意就弄错。
坑点2:统计数位的时候,用Ull才能防止1e18*10爆炸
坑点3:要统计首位为1的区间为0的情况
坑点4:概率是求和,而不是dp[i][j] = max(dp[i-1][j-1] * a[i], dp[i-1][j])
坑点5:如果用ull统计数位的话,最后先转double再相减会失去精度,double会先转化为科学技术法再计算

//
//  Created by Running Photon on 2016-03-13
//  Copyright (c) 2015 Running Photon. All rights reserved.
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define ull unsigned long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-10;
ll n;
double a[maxv];
ull get(ull u) {
    if(u == 0) return 0;
    if(u == 1) return 1;
    ull cnt = 1;
    ull res = 0;
    ull tmp = 1;
    while(tmp * 10 <= u) {
        res += cnt;
        tmp *= 10;
        cnt *= 10;
//        cout << tmp << endl;
    }
    if(u / tmp > 1) res += tmp;
    else res += u % tmp + 1;
    return res;
}
double dp[maxv][maxv];
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
//  ios_base::sync_with_stdio(0);
    while(scanf("%I64d", &n) != EOF) {
        for(int i = 1; i <= n; i++) {
            ll l, r;
            scanf("%I64d %I64d", &l, &r);
            ull R = get(r);
            ull L = get(l - 1);
//            cout << R << ' ' << L << endl;
            a[i] = 1.0 * (R - L) / (r - l + 1.0);
//            printf("a[%d] = %f\n", i, a[i]);
        }
        double k;
        scanf("%lf", &k);
        CLR(dp);
        dp[0][0] = 1;
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j <= i; j++) {
                dp[i][j] = dp[i-1][j] * (1.0 - a[i]);
                if(j)
                    dp[i][j] += dp[i-1][j-1] * a[i];
//                printf("dp[%d][%d] = %f\n", i, j, dp[i][j]);
            }
        }
        double ans = 0;
        for(ll i = 0; i <= n; i++) {
            if((double)100 * i >= k * n - eps) {
//                printf("i = %d\n", i);
                ans += dp[n][i];
            }
        }
        printf("%.10f\n", ans);
    }
//    for(int i = 1; i <= 101; i++) {
//        printf("i = %d  %lld\n", i, get(i));
//    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值