今天整一道概率dp的题来做
题目链接(luogu)
codeforces
题目大意
给一个数 ,然后给出 行,每行 , ,代表第 个数在区间 中,求一个概率使得这 个数中有 %的数是 开头的。
题目思路
啊哈,一看到这个概率,就想到了那段黑暗的时光
咳咳咳,回到正题
首先对于这个区间
之间的数我们可以用差分的方式将它们开头是
的概率求出来
令
表示有
个数的第
位是
的概率
然后呢再用一个概率
,考虑每个区间的贡献,将其求出来
最后再暴力枚举
累加满足条件的概率即可
代码
具体实现见代码
typedef long long ll;
ll count(ll n)
{
ll ans = 0, x = 1, cnt = 0, high = 0, num = n;
while (num)
{
high = num % 10;
num /= 10;
cnt++;
}
cnt--;
for (int i = 1; i <= cnt; i++, x *= 10)
ans += x;
if (high > 1)
ans += x;
else if (high == 1)
ans += n - x + 1;
return ans;
}
const int N = 1005;
double p[N], dp[N], ans;
int n, k;
ll l, r;
int main()
{
ios :: sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> l >> r;
ll tmp = count(r) - count(l - 1);
p[i] = 1.0 * tmp / (r - l + 1);
}
cin >> k;
dp[0] = 1;
for (int i = 1; i <= n; i++)
for (int j = n; j >= 0; j--)
{
dp[j] = dp[j] * (1 - p[i]);//当它不贡献时
if (j > 0)
dp[j] += dp[j - 1] * p[i];
}
for (int i = 0; i <= n; i++)
if (i * 100 >= n * k)
ans += dp[i];
printf ("%.15f", ans);
return 0;
}