http://acm.hdu.edu.cn/showproblem.php?pid=4507
题意:
问一个区间内[L,R]不含7,不是7的倍数,各项相加不是7的倍数的数的平方和为多少
思路:
数位dp的一般套路
dp[pos][sum][sum1],pos代表位,sum代表数字的各项和对7的取模,sum1代表数字对7的取模
唯一难写的是个数的平方怎么写,举个例子
先定义一个结构体
struct node {
LL cnt, sum, sqsum;
node () {}
node (LL cnt_, LL sum_, LL sum1_) {
cnt = cnt_;
sum = sum_;
sqsum = sum1_;
}
};
node dfs(int pos, int sum, int sum1, bool limit) {
node New, Now;
if(!pos) return New = node((sum != 0 && sum1 != 0), 0, 0);
if(!limit && dp[pos][sum][sum1].cnt != -1) return dp[pos][sum][sum1];
int endi = limit ? num[pos] : 9;
Now = node(0, 0, 0);
for (int i = 0; i <= endi; i ++) {
if(i == 7) continue;
New = dfs(pos-1, (sum + i) % 7, (sum1 * 10 + i) % 7, limit && (i == endi));
Now.cnt = (Now.cnt + New.cnt) % M;
Now.sum = (Now.sum + New.sum + New.cnt * i % M * p[pos-1] % M) % M;
Now.sqsum = (Now.sqsum + New.sqsum + 2 * New.sum % M * i % M * p[pos-1] % M) % M;
Now.sqsum = (Now.sqsum + i * i * p[pos-1] % M * p[pos-1] % M * New.cnt % M) % M;
}
return limit ? Now : dp[pos][sum][sum1] = Now;
}
cnt代表有多少满足的数字,sum代表数字各项的和,sqsum代表数字的平方和
那么,现在有 31, 32, 33, 34,假设这4个数满足条件,那么因为是从低位到高位dfs的所以当遍历到3时,发现下面返回来的是一个New结构体,New = {4, 10,30}(解释一下,4代表有1,2,3,4,4个数,10代表1+2+3+4 = 10,30代表
= 30),
(p[pos-1] = )
那么Now的cnt肯定要加上New的cnt代表数字多了这么多,Now的sum加上New的sum并且加上30 X 4( )Now的sqsum加上New的sum2ip[pos-1] + ii*p[pos-1]*p[pos-1])
(
)
由此平方和可以有已知的值得到
那么如果是231,232, 233,234,同样可以有此方法得到
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>
using namespace std;
#define LL long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define inf 1000000000000000000
#define maxn 1005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007
struct node {
LL cnt, sum, sqsum;
node () {}
node (LL cnt_, LL sum_, LL sum1_) {
cnt = cnt_;
sum = sum_;
sqsum = sum1_;
}
}dp[20][10][10];
int num[20];
LL p[20];
node dfs(int pos, int sum, int sum1, bool limit) {
node New, Now;
if(!pos) return New = node((sum != 0 && sum1 != 0), 0, 0);
if(!limit && dp[pos][sum][sum1].cnt != -1) return dp[pos][sum][sum1];
int endi = limit ? num[pos] : 9;
Now = node(0, 0, 0);
for (int i = 0; i <= endi; i ++) {
if(i == 7) continue;
New = dfs(pos-1, (sum + i) % 7, (sum1 * 10 + i) % 7, limit && (i == endi));
Now.cnt = (Now.cnt + New.cnt) % M;
Now.sum = (Now.sum + New.sum + New.cnt * i % M * p[pos-1] % M) % M;
Now.sqsum = (Now.sqsum + New.sqsum + 2 * New.sum % M * i % M * p[pos-1] % M) % M;
Now.sqsum = (Now.sqsum + i * i * p[pos-1] % M * p[pos-1] % M * New.cnt % M) % M;
}
return limit ? Now : dp[pos][sum][sum1] = Now;
}
LL solve(LL n) {
num[0] = 0;
while(n) {
num[++num[0]] = n % 10;
n /= 10;
}
return dfs(num[0], 0, 0, 1).sqsum;
}
int main(int argc, const char * argv[]) {
p[0] = 1;
for (int i = 1; i < 20; i ++)
p[i] = p[i-1] * 10 % M;
for (int i = 0; i < 20; i ++)
for (int j = 0; j < 10; j ++)
for (int k = 0; k < 10; k ++)
dp[i][j][k].cnt = -1;
int T;
scanf("%d", &T);
while(T --) {
LL L, R;
scanf("%lld %lld", &L, &R);
printf("%lld\n", (solve(R) - solve(L-1) + M) % M);
}
return 0;
}