hdu4507(数位DP)

题目意思: 给定一个区间,求这段区间中,不含7,对7取余为0,各个位数相加之和对7取余为0的数的平方和。

设d[i][j][k][m]代表长度为i的,对7取余为j的,各个位数相加之和对7取余为k的数的平方和,

但是算平方和需要用到这些数的和,这些数的个数。所以用了一个结构体数组保存每种状态的Count,sum1,.sum2;

(ago+k1)^2+(ago+k2)^2+(ago+k3)^2=3*ago^2+2*ago*(k1+k2+k3)+k2^2+k2^2+k3^2;

=Count1*ago^2+2*ago*sum1+sum2;

需要注意取模运算和long long

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define MOD 1000000007
#define maxn 20
using namespace std;
const int N=20;
LL  md[N];
LL  digit[maxn];
LL ans=0;
struct node
{
   LL Count=0,sum1=0,sum2=0;
};
node dp[maxn][7][7][2];
int visit[maxn][7][7][2];
node  dfs(int len,int pre,int before, int state,bool fp) //dfs版本的纯属暴力枚举每一个数字,而递推版本的是考虑了前缀的影响
{
    if(state)
         {
             node temp;
             temp.Count=0;
             temp.sum1=0;
             temp.sum2=0;
             return temp;
         }
    if(len==0 && (pre==0 || before==0))
        {
             node  temp;
             temp.Count=0;
             temp.sum1=0;
             temp.sum2=0;
             return temp;
        }
    else if(len==0)
        {
              node  temp;
             temp.Count=1;
             temp.sum1=0;
             temp.sum2=0;
             return temp;
        }
    if(!fp && visit[len][pre][before][state]== 1) //
    {
         return dp[len][pre][before][state];
    }
    node  ret ;
    int  fpmax = fp ? digit[len] : 9 ;
    for(int i=0;i<=fpmax;i++) //分别算出以i开头的数的方案数,
    {
        node next=dfs(len-1,(((pre*10+i))%7) ,(before+i)%7,i==7 | state,fp && i == fpmax);
        //temp=temp%MOD;
        //ret+=(temp*temp)%MOD;
        LL  ago   = ( i*md[len-1] )%MOD;
        ret.Count = (ret.Count +  next.Count) %MOD;
        ret.sum1  = (ret.sum1  + ( ago*next.Count ) %MOD + next.sum1) %MOD;
        ret.sum2  = ( ret.sum2 + (next.Count* ( (ago*ago )%MOD ) ) %MOD +(2*ago*next.sum1)%MOD + next.sum2 ) %MOD;
    }
    if(!fp)
    {
        dp[len][pre][before][state]= ret;
        visit[len][pre][before][state]=1;
    }
    return  ret;
}

LL f(LL n)
{
    int len=0;
    while(n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    LL ans=0;
    ans+=dfs(len,0,0,0,true).sum2;
     return ans;
}
void init()
{
    memset(visit,0,sizeof(visit));
}
int main()
{
   // freopen("test.txt","r",stdin);
    int t;
    scanf("%d",&t);
    md[0]=1;
    for(int i=1;i<=N;i++)
        md[i]=(md[i-1]*10)%MOD;
    while(t--)
    {
        init();
        LL n,m;
        scanf("%I64d%I64d",&n,&m);
         LL ans1=f(m);
         LL ans2=f(n-1);
       printf("%I64d\n", (ans1-ans2 + MOD)%MOD );
    }
    return 0;
}

 

posted on 2015-08-21 21:03  爱装逼的书呆子  阅读(428)  评论(0编辑  收藏  举报

导航