题目链接:HDOJ4507
这个题,跟标准模板就有很多的不一样了,主要体现在数学的计算上面
题意:区间【L,R】内,与7数字无关的数的平方和
无关的定义是:该数不含7,不能被7整除,各个数位之和不是7的倍数
分析:
如果是统计符合某种性质的数的个数,那么很简单
不含7,在数位枚举的时候遇到7跳过就好
被7整除和数位之和是7的倍数,都是在数位枚举完了之后,记忆化的时候一个IF判断就好
统计数的和的题都没有做过,直接上平方和,怎么做呢?
很简单:先从和来想
之前有多少个数符合了要求,每个数位上的值是多少,先加起来
平方和呢:(a+b)^2=a^2+b^2+2*a*b
(a + b)^2 = a^2 + 2*a*b + b^2可以得出(数位上的对应值 * (能满足的条件的数的数量) + 2 * sigma((每个分支下面满足条件的数量)*(分支和)) + sigma(分支平方和)。
所以,要求平方和,各个数的和也得先求出来
按照这个思路,dp【pos】【sum】【num】就需要做改动,变成一个结构体
需要保存三个数:当前满足条件的数的个数,数的和,数的平方和
所以,需要预处理每一个数位上的值,每个数位在表示数的时候是有权值的,十位数上的数权重为10,以此类推
预处理权重数组
#include<map>
#include<set>
#include<math.h>
#include<time.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define ll rt<<1
#define rr rt<<1|1
#define LL long long
#define ULL unsigned long long
#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)
const long long MOD=1000000007LL;
struct Node{
long long cnt;
long long sum;
long long sqsum;
}dp[20][10][10];
int digit[20];
long long p[20];
Node dfs(int pos,int sum,int num,bool flag){
Node ans,tmp;
if (pos==0){
tmp.cnt=(sum!=0&&num!=0);
tmp.sum=tmp.sqsum=0;
return tmp;
}
if (flag&&dp[pos][sum][num].cnt!=-1) return dp[pos][sum][num];
int maxnumber=flag?9:digit[pos];
ans.cnt=ans.sum=ans.sqsum=0;
for(int i=0;i<=maxnumber;i++){
if (i==7) continue;
tmp=dfs(pos-1,(sum+i)%7,(num*10+i)%7,flag||i<maxnumber);
ans.cnt+=tmp.cnt;
ans.cnt%=MOD;
ans.sum+=(tmp.sum+((p[pos]*i)%MOD)*tmp.cnt%MOD)%MOD;
ans.sum%=MOD;
ans.sqsum+=(tmp.sqsum+((2*p[pos]*i)%MOD)*tmp.sum)%MOD;
ans.sqsum%=MOD;
ans.sqsum+=(tmp.cnt*p[pos])%MOD*p[pos]%MOD*i*i%MOD;
ans.sqsum%=MOD;
}
if (flag) dp[pos][sum][num]=ans;
return ans;
}
long long calc(long long n){
int len=0;
while(n){
digit[++len]=n%10;
n/=10;
}
return dfs(len,0,0,0).sqsum;
}
int main(){
//input;
int T;
long long l,r,ans;
p[1]=1;
for(int i=2;i<20;i++)
p[i]=(p[i-1]*10)%MOD;
memset(dp,0,sizeof(dp));
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;
scanf("%d",&T);
while(T--){
scanf("%I64d%I64d",&l,&r);
ans=calc(r);
ans-=calc(l-1);
ans=(ans%MOD+MOD)%MOD;
printf("%I64d\n",ans);
}
return 0;
}