HDU 4507 吉哥系列故事——恨7不成妻(数位DP)

这道题是开始思路错了….然后看了kuangbin巨巨的blog,但是感觉看不懂….所以找了其他blog很久才略懂一些
题意:中文题…
思路:
这里我们举个例子是L=111,R=113,恩
解释一下最后一个式子,就是求平方和的
答案就是111^2+112^2+113^2,然后我们枚举每一位的话,我们要把一个数拆开
比如113这个数,我们dfs完了后边的13,我们看回到100的时候怎么处理
就是100+13,113^2=(1* 100+13)^2
=1* 1* 100* 100* tmp.cnt(有多少种情况当前位置是1)+(1* 100* 13)*2+13^2
=i* i* p[pos]* p[pos]* tmp.cnt+(i* p[pos]* tmp.sum)*2+tmp.sqsum
感觉解释的比较清楚了
第二步的式子代码中有解释,OVER
为了以防表达能力太弱还是给几个链接....
http://www.tuicool.com/articles/z2uQri
http://fszxwfy.blog.163.com/blog/static/44019308201332761933868/
http://blog.csdn.net/acm_cxlove/article/details/8707084
我就是结合了上边三个的blog才看懂的

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<vector>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm> 
using namespace std;
typedef long long LL;
#define maxn 1005
#define f(x) (x*1.0)
#define inf 0x3f3f3f3f
#define maxm maxn*maxn
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define lowbit(x) (x&(-x))
#define cheak(i) printf("%d ",i)
#define lson(x) (splay[x].son[0])
#define rson(x) (splay[x].son[1])
#define rfor(i,a,b) for(i=a;i<=b;++i)
#define lfor(i,a,b) for(i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define mec(a,b) memcpy(a,b,sizeof(b))
const LL mod=1e9+7;
int A[50];
struct node
{
    LL cnt,sum,sqsum;
    void init()
    {
        cnt=sum=sqsum=0;
    }
}dp[20][10][10];
LL p[20];
//1 数中有7
//2 数位和是7的倍数
//3 数是7的倍数 
node dfs(int pos,int Mod,int sum,bool edge)
{
    if(pos==-1) 
    {
        node tmp;
        tmp.cnt=Mod!=0&&sum!=0;
        tmp.sum=tmp.sqsum=0;
        return tmp;
    }
    if(!edge&&dp[pos][Mod][sum].cnt!=-1)
    return dp[pos][Mod][sum];
    int end=edge?A[pos]:9;
    int i;
    node ans,tmp;
    ans.init();
    rfor(i,0,end)
    if(i!=7)
    {
        tmp=dfs(pos-1,(Mod+i)%7,(sum*10+i)%7,edge&&i==end);

        ans.cnt+=tmp.cnt;
        ans.cnt%=mod;
        //这个...就不用解释了... 

        ans.sum+=(tmp.sum+(p[pos]*i)%mod*tmp.cnt%mod)%mod;
        //这个式子能拆成两部分
        //1.tmp.sum是代表后边pos-1,pos-2....0的位数的和 
        //2. (p[pos]*i)*tmp.cnt是在这个位数是当前这个值得时候有tmp.cnt种情况
        //所以只针对当前位数 
        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(!edge) dp[pos][Mod][sum]=ans;
    return ans;
}
long long solve(long long n)
{
    int pos=0;
    while(n)
    {
        A[pos++]=n%10;
        n/=10;
    }
    return dfs(pos-1,0,0,1).sqsum;
}
int main()
{
    int T,i,j,k;
    LL l,r;
    rfor(i,0,19)
     rfor(j,0,6)
      rfor(k,0,6)
      dp[i][j][k].cnt=-1;
    p[0]=1;
    rfor(i,1,19) p[i]=p[i-1]*10%mod;
 scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&l,&r);
        LL ans=solve(r)-solve(l-1);
        ans=(ans%mod+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(HDU,数位dp,HDU4507)