[c]代码库
/*
2013腾讯马拉松初赛第1场
1003 吉哥系列故事——恨7不成妻
Time Limit: 0.5 Seconds Memory Limit: 65536K
单身!
依然单身!
吉哥依然单身!
DS级码农吉哥依然单身!
所以,他生平最恨情人节,不管是214还是77,他都讨厌!
吉哥观察了214和77这两个数,发现:
2+1+4=7
7+7=7*2
77=7*11
最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数!
什么样的数和7有关呢?
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1.整数中某一位是7;
2.整数的每一位加起来的和是7的整数倍;
3.这个整数是7的整数倍;
现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
Input
输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。
Output
请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。
Sample Input
3
1 9
10 11
17 17
Sample Output
236
221
0
*/
/*
解题报告:
这题的数据范围很大,如果直接模拟的话肯定超时,还有这题时限好像还是500MS的,故意搞不这样就是不让一般的暴力方法过这题。
这题和以前不一样的地方在他要求的是平方和,而不是和。以前求和还是好做的。
一般这种题目的话肯定是数位DP了。
第一种想法,上面有三个条件,我们可以先用上面的条件求出至少符合一个条件的数字平方和。这个要用一下容斥原理。比较麻烦。
我是直接把7这一位数字去掉,然后再加两维状态保存当前数字对7取余的结果,和每一位之和对7取余的结果。
下面说一下我的做法。
dp[i][j][p][q]表示长度为i的以j为首位的数字每一位数字之和对7取余是p,整个数字对7取余是q的平方和。
现问题的关键是如何通过dp[i-1][k][a][b]推出来dp[i][j][p][q]
我们可以观察,假设dp[i-1][k][a][b]里面的数字是
n1,n2,...n[T] dp[i-1][k][a][b]这个状态下有T个数字是合法的
那么dp[i][j][p][q]状态下的数字就是
j*ten[i-1]+n1,j*ten[i-1]+n2,...j*ten[i-1]+n[T]
ten[i]代表10的i次方
他们的平方和就是
(j*ten[i-1]+n1)^2+(j*ten[i-1]+n2)^2+...+(j*ten[i-1]+n[T])^2
展开一下
T*(j*ten[i-1])^2+2*j*ten[i-1]*(n1+n2+...+n[T])+n1^2+n2^2+n3^2+...+n[T]^2
从上面的式子可以看出,要计算出平方和,还需要统计一下合法数字的个数,还有,这些合法数字的总和。
所以我们要分三步DP。
dp复杂度是O(20*10*10*7*7),对于50个数据还是可以接受的。
来自:chenwenwen0210 的百度空间
*/
#include<stdio.h>
#include<time.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef __int64 lld;
const int MAX = 510000;
const int INF = 1000000000;
const lld MOD = 1000000007;
lld dp[20][10][7][7] = {0};
lld cnt[20][10][7][7] = {0};
lld sum[20][10][7][7] = {0};
lld multi[10][10];
lld add[10][10];
lld ten[20];
lld tp[20];
void init() {
lld i, j, p, q, k;
lld a, b;
cnt[0][0][0][0] = 1;
//计算个数
for(i = 1; i < 20; i++) {
for(j = 0; j < 10; j++) {
if(j == 7)continue;
for(a = 0; a < 7; a++) {
for(b = 0; b < 7; b++) {
if(cnt[i - 1][j][a][b] == 0)continue;
for(k = 0; k < 10; k++) {
if(k == 7)continue;
p = add[k][a]; //加起来对7取余
q = multi[k][ten[i - 1]]; //乘起来对7取余
q = add[q][b];
cnt[i][k][p][q] += cnt[i - 1][j][a][b];
if(cnt[i][k][p][q] >= MOD)cnt[i][k][p][q] -= MOD;
}
}
}
}
}
//计算和
for(i = 1; i < 20; i++) {
for(j = 0; j < 10; j++) {
if(j == 7)continue;
for(a = 0; a < 7; a++) {
for(b = 0; b < 7; b++) {
for(k = 0; k < 10; k++) {
if(k == 7)continue;
p = add[k][a];
q = multi[k][ten[i - 1]];
q = add[q][b];
lld z = k * tp[i - 1] % MOD;
sum[i][k][p][q] += cnt[i - 1][j][a][b] * z + sum[i - 1][j][a][b];
if(sum[i][k][p][q] >= MOD)sum[i][k][p][q] %= MOD;
}
}
}
}
}
//计算平方和
for(i = 1; i < 20; i++) {
for(j = 0; j < 10; j++) {
if(j == 7)continue;
for(a = 0; a < 7; a++) {
for(b = 0; b < 7; b++) {
for(k = 0; k < 10; k++) {
if(k == 7)continue;
p = add[k][a];
q = multi[k][ten[i - 1]];
q = add[q][b];
lld z = k * tp[i - 1] % MOD;
dp[i][k][p][q] += cnt[i - 1][j][a][b] * z % MOD * z + dp[i - 1][j][a][b] + 2 * z * sum[i - 1][j][a][b];
if(dp[i][k][p][q] >= MOD)dp[i][k][p][q] %= MOD;
}
}
}
}
}
}
lld split(lld bit[], lld n) {
int i = 0;
for(i = 0; n; i++) {
bit[i] = n % 10;
n /= 10;
}
return i;
}
bool ok(lld n) {
if(n % 7 == 0)return false;
lld sum = 0;
while(n) {
if(n % 10 == 7)return false;
sum += n % 10;
n /= 10;
}
if(sum % 7 == 0)return false;
return true;
}
lld calc(lld n) {
if(n == 0)return 0;
lld bit[22], len;
lld ret = 0;
lld i, j, k, p, q, a, b;
len = split(bit, n);
if(ok(n))ret += n % MOD * (n % MOD) % MOD;
for(i = 1; i < len; i++) {
for(j = 1; j < 10; j++) {
if(j == 7)continue;
for(p = 1; p < 7; p++) {
for(q = 1; q < 7; q++) {
ret += dp[i][j][p][q];
if(ret >= MOD)ret -= MOD;
}
}
}
}
lld presum = 0; //前面各位和对7取余
lld premod7 = 0; //前面组成数字对7取余
lld pre = 0; //前面组成数字对MOD取余
for(i = len; i >= 1; i--) {
j = 0;
if(i == len)j++;
for(; j < bit[i - 1]; j++) {
if(j == 7)continue;
for(k = 0; k < 10; k++) {
if(k == 7)continue;
for(a = 0; a < 7; a++) {
for(b = 0; b < 7; b++) {
p = add[presum][j];
p = add[p][a];
if(p == 0)continue;
q = multi[premod7][10 - 7];
q = add[q][j];
q = multi[q][ten[i - 1]];
q = add[q][b];
if(q == 0)continue;
lld z = (pre * 10 + j) * tp[i - 1] % MOD;
ret += z * z % MOD * cnt[i - 1][k][a][b] + dp[i - 1][k][a][b] + 2 * z * sum[i - 1][k][a][b];
ret %= MOD;
}
}
}
}
if(bit[i - 1] == 7)break;
pre = (pre * 10 + bit[i - 1]) % MOD;
presum = add[presum][bit[i - 1]];
premod7 = multi[premod7][10 - 7];
premod7 = add[premod7][bit[i - 1]];
}
return ret;
}
int main() {
lld n, m;
int i, j;
int T = 0;
for(i = 0; i < 10; i++) {
for(j = 0; j < 10; j++) {
add[i][j] = (i + j) % 7;
multi[i][j] = i * j % 7;
}
}
ten[0] = 1;
tp[0] = 1;
for(i = 1; i < 20; i++) {
ten[i] = ten[i - 1] * 10 % 7;
tp[i] = tp[i - 1] * 10 % MOD;
}
init();
scanf("%d", &T);
while(T--) {
scanf("%I64d%I64d", &n, &m);
lld ans = 0;
ans += calc(m);
ans -= calc(n - 1);
if(ans < 0)ans += MOD;
printf("%I64d\n", ans);
}
return 0;
}
by: 发表于:2017-08-11 10:09:17 顶(0) | 踩(0) 回复
??
回复评论