最近在练习数位dp,觉得自己很水很菜,就这道题我做了三天!!
其实如果是求个数有多少,相信很多人都会做。。因为这就是很简单的数位dp
但是它加了求平方和。。如果你是在平时的基础上改一下就会错了。。
主要是求平方和:
(tem+B1)^2 + (tem+B2)^2 + (tem+B3)^2 + ……(tem+Bn)^2 = tem^2*n + 2*tem(B1+B2+……Bn) + (B1^2 +B2^2+……+Bn^2)
这里的意思是假如有一个数 9535425471 DFS到2时 那其实我们是想求以2开头的5位数满足
情况的平方和,所以tem就为20000,而Bi就是递归下去找和20000匹配且满足要求的平方和
就是上面这一条公式了
#include
#include
const __int64 MOD = 1e9+7;
typedef struct node
{
__int64 nn;
__int64 sum,sqsum;
int flag;
};
node dp[31][10][10][3];
__int64 l,r;
__int64 po[22];
int m[22];
void Init()
{
int i,k,j,r;
po[0] = 1;
for(i=1;i<22;i++)
po[i] = (10*po[i-1])%MOD;
for(i=0;i<30;i++)
for(j=0;j<10;j++)
for(k=0;k<10;k++)
for(r=0;r<3;r++)
{
dp[i][j][k][r].nn = dp[i][j][k][r].sum = dp[i][j][k][r].sqsum =dp[i][j][k][r].flag=0;
}
}
int tran(__int64 p)
{
memset(m,0,sizeof(m));
int b = 1;
while(p)
{
m[b++] = p%10;
p = p/10;
}
return b-1;
}
node DFS(int len,int flag1,int f,int p,int doing)//flag1是否有7,f后面的数之和
{ //p后面的数平方之和
node kk;
kk.flag = kk.nn = kk.sqsum = kk.sum = 0;
if(len==0)
{
if(!flag1 && f!=0 && p!=0)
{
kk.nn = 1;
return kk;
}
else
return kk;
}
if(!doing && dp[len][f][p][flag1].flag)
return dp[len][f][p][flag1];
int end = doing?m[len]:9;
node var1,var2;
var1.sum = var1.sqsum = var1.nn = var1.flag = 0;
var2.sum = var2.sqsum = var2.nn = var2.flag = 0;
for(int i=0;i<=end;i++)
{
var1 = DFS(len-1,i==7?1:flag1,(f+i)%7,(p*10+i)%7,doing&&(i==end));
__int64 tem = (i*po[len-1])%MOD;
var2.nn = (var1.nn+var2.nn)%MOD;
var2.sum = (tem*var1.nn%MOD+var1.sum+var2.sum)%MOD;
var2.sqsum = ( ((tem*tem)%MOD*var1.nn)%MOD + (2*tem*var1.sum)%MOD + var1.sqsum +var2.sqsum )%MOD;
}
if(!doing)
{
var2.flag = 1;
dp[len][f][p][flag1] = var2;
}
return var2;
}
int main()
{
int t;
Init();
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d",&l,&r);
__int64 ll = DFS(tran(l-1),0,0,0,1).sqsum;
__int64 rr = DFS(tran(r),0,0,0,1).sqsum;
printf("%I64d\n",(rr-ll+MOD)%MOD);
}
return 0;
}