HDU-4507 吉哥系列故事——恨7不成妻 数位DP
思路:想必普通的统计满足条件的个数都会吧,这里就不在赘述了,
dp[i][j][k]代表长度为i,数字对7取余数为j,数字各个位数加起来对7取余数k;仅仅用dp[i][j][k]的值代表个数是不能得到答案的,还要统计满足条件的和还有平方和;
开结构体,维护和的时候假如是算332+321则可以拆分为300*2(就是以3开头的长度为3的有多少个)+(32+21)(长度为2的和);按照这样则每一次深搜完关于某个长度开头为x的都可以直接计算其和;
平方和则是,假如算的是332的平方+321的平方 (300的平方)* 2(以3开头长度为3的有多少个)+(32平方+21平方)(长度为2的平方和)+(2*300*(32+21)(长度为2的和));这是跟据平方和的公式推出来的
(x+y)2
=
x2
+
y2
+
2∗x∗y
;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int Mod=1e9+7;
struct zp
{
LL cnt,sum,squasum;
zp()
{
cnt=-1;
sum=0;
squasum=0;
}
} dp[30][10][10];
int x[100];
LL cf[100];
zp dfs(int len,int num,int mod,int flag)
{
zp ans;
ans.cnt=ans.squasum=ans.sum=0;//不要忘记这一步,应为出事化的cnt为-1;
if(len==-1)
{
zp w;
w.cnt=(mod!=0&&num!=0);
w.squasum=w.sum=0;
return w;
}
if(!flag&&dp[len][num][mod].cnt!=-1) return dp[len][num][mod];
int stop=flag?x[len]:9;
for(int i=0; i<=stop; i++)
{
if(i==7)
continue;
zp temp=dfs(len-1,(num*10+i)%7,(mod+i)%7,flag&&i==stop);
ans.cnt+=temp.cnt;
ans.cnt%=Mod;
LL o=i*cf[len]%Mod;
ans.sum+=(o*temp.cnt%Mod+temp.sum)%Mod;
ans.sum%=Mod;
ans.squasum+=o*o%Mod*temp.cnt%Mod+temp.squasum%Mod+2*temp.sum%Mod*o%Mod;
ans.squasum%=Mod;
}
if(!flag) dp[len][num][mod]=ans;
return ans;
}
zp solve(LL n)
{
int cont=0;
memset(x,0,sizeof(x));
while(n)
{
x[cont++]=n%10;
n/=10;
}
return dfs(cont-1,0,0,1);
}
int main()
{
cf[0]=1;
for(int i=1; i<=20; i++)
cf[i]=(cf[i-1]*10)%Mod;
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
LL n,m;
cin>>n>>m;
cout<<(solve(m).squasum%Mod-solve(n-1).squasum%Mod+Mod)%Mod<<endl;
}
}