题意:在一定区间内和7无关的数字的平方和。
思路:这种醉醉的题目,也是醉醉的。
其实理解了,就醒了~
首先只求有多少个数,那么大家肯定都会了。
但是这里我们对于dp[site][mod][sum] 要维护3个东西,n:有多少个数、sum:这些数的和、sumqrt这些数的平方和。
我们通过递归,n就是我们大家都会的那个东西,那么对于这些数的和。
举个例子,比如求12
那就是0~12的和。
0:0~9
1:0~2
这两段。
那么我们如果知道0~9的和又知道有10个数 那么他们的和便是 0*10*10+sum(0~9)
然后是0~2的和又知道有3个数 再加上 1*10*3+sum(0~2) 这两个加起来就是0~12的和了
其中0,1就是当前位是什么,10就是对应的10^(site-1),10、3就是多少个数。
想想其实是很好理解的。
那么我们再来看平方和。
为了方便 我们把当前位乘上10对应的次方 设为tep
然后设x1~xn为却掉高位所剩下的数。
那么当前的平方和 就等于 (tep+x1)^2+(tep+x2)^2+...+(tep+xn)^2
展开便是 n*tep^2+2*tep*(x1+x2+..+xn)+(x1^2+x2^2+..+xn^2) n是个数
那么这样递归下去知道 sum和sumqrt都是一个数 就ok了~
然后就是注意各个地方记得取模 不要溢出了!
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"stack"
#include"algorithm"
#include"iostream"
using namespace std;
int m=1000000007;
struct node
{
int f;
__int64 n,sum,sumqrt;
node()
{
f=-1; //特意弄个f 表示是否记忆过
n=sum=sumqrt=0;
}
}dp[22][10][10];
int num[22];
__int64 ten[22];
node dfs(int site,int mod,int sum,int f)
{
if(site==0)
{
node a;
if(mod!=0&&sum!=0) a.n=1; //到最后如果是 就是一个数~
return a;
}
if(!f&&dp[site][mod][sum].f!=-1) return dp[site][mod][sum];
int len=f?num[site]:9;
node cur,next;
for(int i=0;i<=len;i++)
{
if(i==7) continue;
__int64 tep=i*ten[site]%m;
cur=dfs(site-1,(mod*10+i)%7,(sum+i)%7,f&&i==len);
next.n=(next.n+cur.n)%m;
next.sum=(next.sum+tep*cur.n+cur.sum)%m;
next.sumqrt=(next.sumqrt+((tep*tep%m)*cur.n)%m+(2*tep*cur.sum)%m+cur.sumqrt)%m;// 注意取模
}
if(!f)
{
next.f=1;
dp[site][mod][sum]=next;
}
return next;
}
node solve(__int64 x)
{
int cnt=0;
while(x)
{
num[++cnt]=x%10;
x/=10;
}
return dfs(cnt,0,0,1);
}
int main()
{
int t;
cin>>t;
ten[1]=1;
for(int i=2;i<=20;i++) ten[i]=(ten[i-1]*10)%m; //记得取模
while(t--)
{
__int64 x,y;
__int64 ans=0;
scanf("%I64d%I64d",&x,&y);
ans=(solve(y).sumqrt-solve(x-1).sumqrt)%m;
printf("%I64d\n",(ans+m)%m); //记得有可能是负数,要化成正的
}
return 0;
}
原文地址:http://blog.csdn.net/wdcjdtc/article/details/39230413