【数位DP】HDU4507[吉哥系列故事——恨7不成妻]题解

题目概述

[L,R] 中同时满足[1.不存在 7 。2.不是 7 的倍数。3.每位加起来不是 7 的倍数。]的数的平方和

解题报告

恩……又是数位DP水……水个头啊,平方和是什么鬼???

这道题要用平方和公式 (a+b)2=a2+2ab+b2 来统计答案,对于每个状态,记录三个量: num 表示该状态的方案数, sum 表示该状态所有方案的数的总和, sqr 表示该状态所有方案的数的平方的总和。

然后将一个数 x 看做每位相加,比如:

12=1×101+2×100122=(10+2)2=102+2×10×2+22

这样就可以方便的转移了。详细一点?不如膜拜ChesterKing

发现记忆化真的好写……感觉又重学了一遍数位DP……

示例程序

#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn=19,MOD=1e9+7;

int te,a[maxn+5];LL L,R,p[maxn+5];
inline void AMOD(LL &x,LL tem) {if ((x+=tem)>=MOD) x-=MOD;}
#define Mod(x) ((x)%MOD)
struct data
{
    LL num,sum,sqr;data(LL A=-1,LL B=-1,LL C=-1) {num=A;sum=B;sqr=C;}
    void Add(const data &c,int i,int x)
    {
        AMOD(num,c.num);AMOD(sum,Mod(c.sum+Mod(p[x]*c.num)*i));
        AMOD(sqr,Mod(c.sqr+Mod(p[x]*c.sum)*i*2+Mod(Mod(Mod(p[x]*i)*Mod(p[x]*i))*c.num)));
    }
};
data f[maxn+5][7][7];

void Make() {p[0]=1;for (int i=1;i<=maxn;i++) p[i]=Mod(p[i-1]*10);}
data Dfs(int i,int A,int M,bool fl)
{
    if (!i) return data(A&&M,0,0);if (!fl&&~f[i][A][M].sqr) return f[i][A][M];
    int MAX=9;if (fl) MAX=a[i];data ans=data(0,0,0);
    for (int j=0;j<=MAX;j++) if (j!=7)
        ans.Add(Dfs(i-1,(A+j)%7,((M<<3)+(M<<1)+j)%7,fl&&j==MAX),j,i-1);
    if (!fl) f[i][A][M]=ans;return ans;
}
inline int Solve(LL n)
{
    a[0]=0;do a[++a[0]]=n%10,n/=10; while (n);
    return Dfs(a[0],0,0,true).sqr;
}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    for (Make(),scanf("%d",&te);te;te--) scanf("%lld%lld",&L,&R),printf("%d\n",Mod(Solve(R)+MOD-Solve(L-1)));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值