6062. 【GDOI2019模拟2019.3.16】计算(数位DP+exp的性质)

博客围绕k不含m子串∑ek/n(n,m≤109)的问题展开。指出这是经典数位DP问题,用fi,j,0/1,0/1表示构造到第i位等状态。提到C++里exp(k)=ek且精度高,转移利用ex+y=exp(x)∗exp(y)性质,最后提醒注意m=0时前导0情况。

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

Problem

∑k不含m子串ek/n\sum_{k不含m子串}e^{k/n}kmek/n

n,m≤109n,m\le 10^9n,m109

Solution

经典数位DP。

fi,j,0/1,0/1f_{i,j,0/1,0/1}fi,j,0/1,0/1 表示构造到第iii位,匹配到第jjj位,是否达上届,是否是前导000.

C++里exp(k)=ekexp(k)=e^kexp(k)=ek,且精度很高。

转移注意一个显然的性质是ex+y=exp(x)∗exp(y)e^{x+y}=exp(x)*exp(y)ex+y=exp(x)exp(y).

最后注意当m=0m=0m=0时的前导000

Code
#include <bits/stdc++.h>

#define F(i, a, b) for (int i = a; i <= b; i ++)
typedef double db;

using namespace std;

char s[12], t[12];
int n, m, a[12], b[12], sum, ten[12], nx[12];
db f[12][12][2][2], ans;

int main() {
	freopen("calc.in", "r", stdin);
	freopen("calc.out", "w", stdout);

	scanf("%s%s", s + 1, t + 1);
	n = strlen(s + 1), m = strlen(t + 1), ten[0] = 1;
	F(i, 1, n) a[i] = s[i] - '0', sum = sum * 10 + a[i], ten[i] = ten[i - 1] * 10;
	F(i, 1, m) b[i] = t[i] - '0';
	
	int j = 0;
	F(i, 2, m) {
		while (j && b[j + 1] != b[i]) j = nx[j];
		if (b[j + 1] == b[i]) j ++;
		nx[i] = j;
	}

	f[1][0][0][1] = 1;
	F(x, 1, a[1]) {
		if (m == 1 && x == b[m]) continue;
		f[1][x == b[1]][x == a[1]][0] += exp((db)x * ten[n - 1] / sum);;
	}
	F(i, 1, n - 1) F(j, 0, m - 1)
		F(p, 0, 1) F(q, 0, 1) if (f[i][j][p][q])
			F(x, 0, ((p == 1) ? (a[i + 1]) : (9))) {
				if (q == 1 && x == 0 && b[1] == 0)
					f[i + 1][0][0][1] += f[i][j][p][q];
				if (j == m - 1 && x == b[m])
					continue;
				if (q == 1) {
					f[i + 1][x == b[1]][0][x == 0] += f[i][j][p][q] * exp((db) x * ten[n - i - 1] / sum);
				}
				else {
					int y = j;
					while (y && b[y + 1] != x) y = nx[y];
					if (b[y + 1] == x) y ++;
					
					f[i + 1][y][(p == 1) & (a[i + 1] == x)][0] += f[i][j][p][q] * exp((db) x * ten[n - i - 1] / sum);
				}
			}
	F(j, 0, m - 1)
		ans = (ans + f[n][j][0][0] + f[n][j][0][1] + f[n][j][1][0] + f[n][j][1][1]);
	printf("%.3lf\n", ans - 1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值