您的位置:首页 > 理论基础 > 计算机网络

WUST OJ 1579 Camellia(数位dp)

2016-04-16 22:11 405 查看
题意:给出一个区间,求出这个区间内所有数的数位方差之和。数位方差定义为将一个数的每位数字看成一串随机变量的方差。

题目链接:WUST OJ 1579 Camellia

思路:数位dp。

首先可以化简求方差和的公式,对于所有长度为n,和为s,每位数可以任意去0-9的数(可以有前导0),首先假设这样的数有t个,那么他们的方差和为

(n*sigma(x*2)+ t*s*s)乘以n^2的逆元,也就是说问题转化成了求这样的数的集合的数位平方和sigma(x*2)和数量t。

可以dp预处理出对于长度为n,和为s的这些数的数量和个数,然后枚举数字的长度,然后对于小于原长度的每一个长度,枚举首位数字和数位和来计算方差和

对于原长度,因为要考虑是否和当前前缀相同,所以可以用数位dp来做,dfs的三维分别表示当前位置,当前的数位和,当前数位平方和,以及当前是否是第一个位置的标记。

#include<bits/stdc++.h>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#define pb push_back
#define mp make_pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 100;
//const int INF = 0x3f3f3f3f;
const LL MOD = 1e9 + 7;
int n;
LL dp1[11][MAXN], dp2[11][MAXN], inv[MAXN];
int d[20], len;
LL ans, jiecheng;
LL pow_mod(int a, int b) {
if (!b) return 1;
LL ans = pow_mod(a, b/2);
ans = ans*ans % MOD;
if (b&1) ans = ans * a % MOD;
return ans;
}

void init_inv() {
for (int i = 0; i <= 9*9; i++)
inv[i] = pow_mod(i, MOD-2);
}
void init_dp() {
dp1[0][0] = 0;
dp2[0][0] = 1;
for (int i = 1; i <= 9; i++) {
int maxs = i*9;
for (int j = maxs; j >= 0; j--) {
for (int k = 0; k < 10 && j-k >= 0; k++) {
dp1[i][j] = (dp1[i][j] + dp1[i-1][j-k] + dp2[i-1][j-k]*k*k) % MOD;
dp2[i][j] = (dp2[i][j] + dp2[i-1][j-k]) % MOD;
}
}
}
jiecheng = 1;
for (int i = 1; i <= 9; i++)
jiecheng *= i;
jiecheng %= MOD;
}
void init_input(int num) {
len = 0;
while (num) {
d[++len] = num % 10;
num /= 10;
}
}

LL dfs(int pos, int sum, int p, bool start) {
if (!pos)
return (len*p-sum*sum)*inv[len*len] % MOD;
LL ans = 0;
int i = start ? 1 : 0;
for (; i < d[pos]; i++) {
int maxs = (pos-1) * 9;
for (int j = maxs; j >= 0; j--)
ans = (ans + ((dp1[pos-1][j]+dp2[pos-1][j]*(p+i*i))*len - dp2[pos-1][j]*(sum+i+j)*(sum+i+j))%MOD*inv[len*len]) % MOD;
}
ans = (ans + dfs(pos-1, sum+d[pos], p+d[pos]*d[pos], false)) % MOD;
return ans;
}
LL solve(int num) {
if (!num) return 0;
init_input(num);
ans = 0;
for (int i = len-1; i; i--) {
for (int j = 1; j <= 9; j++) {
int maxs = (i-1)*9;
for (int k = maxs; k >= 0; k--)
ans = (ans + ((dp1[i-1][k]+dp2[i-1][k]*j*j)*i - dp2[i-1][k]*(k+j)*(k+j))%MOD*inv[i*i]) % MOD;
}
}
//cout << ans << endl;
ans = (ans + dfs(len, 0, 0, true)) % MOD;
}
int main()
{
//freopen("input.txt", "r", stdin);
init_inv();
init_dp();
int T;
scanf("%d", &T);
//cout << jiecheng << endl;
//cout << dp2[2][17] << endl;
while (T--) {
int l, r;
scanf("%d%d", &l, &r);
LL ans1 = solve(r);
LL ans2 = solve(l-1);
//cout << ans1 << " " << ans2 << endl;
LL ans3 = (ans1-ans2)*jiecheng%MOD*jiecheng%MOD + MOD;
//cout << inv[4] << endl;
printf("%lld\n", ans3%MOD);
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息