基础教学 + 初探hdu2089题解:http://blog.csdn.net/techmonster/article/details/50273967
进阶 【重要模板】(数位dp几乎都是这个模板):http://blog.csdn.net/techmonster/article/details/50275783
数位DP 优秀题目 hdu 4507 (注意,仍是上面的模板)
利用数学方法,将平方展,然后加和。
另外还有一道数位DP 的毕业题 hdu 1633,表面看起来简单实际上考虑的非常复杂:http://blog.csdn.net/techmonster/article/details/50298937
hdu 4507 代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MS(x,y) memset(x,y,sizeof(x))
#define pi acos(-1.0)
using namespace std;
void fre(){freopen("t.txt","r",stdin);}
typedef long long LL;
typedef unsigned long long ULL;
const int MOD = 1e9 + 7;
const int inf = (1<<63)-1;
const double eps = -(1<<30);
struct node
{
LL ssum,sum,num;//ssum为平方和,sum为和,num为符合条件的数字个数
node()
{
ssum = 0; sum = 0; num = 0;
}
}dp[20][10][10];// 表示i位数,余数为j,各位数字和的余数为k 的状态
bool vis[20][10][10]; //表示 对应dp是否被访问
int digit[20];
LL pow10[20];
node dfs(int len,int mod,int smod,int flag)
{
if(len == 0) //len==0 表示搜索结束
{
if(mod==0 || smod==0) {node a;a.ssum = a.sum = a.num = 0; return a;}
else {node a;a.ssum = a.sum = 0; a.num = 1;return a;}
}
if(!flag && vis[len][mod][smod] == 1) return dp[len][mod][smod];
int i,j,top;
node res,ttt;
top = flag?digit[len]:9;
for(i = 0; i <= top; ++i)
{
if(i == 7) continue;
int _mod,_smod;
_mod = (10*mod + i)%7;
_smod = (smod + i)%7;
ttt = dfs(len-1,_mod,_smod,flag&&top==i);
LL tem = i*pow10[len-1]%MOD;
res.num =(res.num + ttt.num)%MOD;
res.sum = (res.sum + (ttt.sum+(ttt.num*tem)%MOD)%MOD)%MOD;
res.ssum = (res.ssum +((ttt.ssum + 2*tem%MOD*ttt.sum)%MOD + (tem*tem%MOD*ttt.num)%MOD ))%MOD;
}
if(!flag) {dp[len][mod][smod] = res;vis[len][mod][smod]=1;}
return res;
}
LL calc(LL x)
{
int len = 0;
while(x != 0)
{
digit[++len] = x % 10;
x/=10;
}
node tem=dfs(len,0,0,1);
return tem.ssum;
}
int main()
{
// fre();
int t;
LL l,r;
pow10[0] = 1;
for(int i = 1; i < 19; ++i) pow10[i] = (pow10[i-1]*10)%MOD;
scanf("%d",&t);
MS(dp,0);
while(t--)
{
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",(calc(r)-calc(l-1)+MOD)%MOD);//此处防止负数,要+MOD
}
return 0;
}