数位dp(恨7不成妻)

HDU-4507 吉哥系列故事——恨7不成妻 数位DP
思路:想必普通的统计满足条件的个数都会吧,这里就不在赘述了,
dp[i][j][k]代表长度为i,数字对7取余数为j,数字各个位数加起来对7取余数k;仅仅用dp[i][j][k]的值代表个数是不能得到答案的,还要统计满足条件的和还有平方和;
开结构体,维护和的时候假如是算332+321则可以拆分为300*2(就是以3开头的长度为3的有多少个)+(32+21)(长度为2的和);按照这样则每一次深搜完关于某个长度开头为x的都可以直接计算其和;
平方和则是,假如算的是332的平方+321的平方 (300的平方)* 2(以3开头长度为3的有多少个)+(32平方+21平方)(长度为2的平方和)+(2*300*(32+21)(长度为2的和));这是跟据平方和的公式推出来的 x+y2 = x2 + y2 + 2xy

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int Mod=1e9+7;
struct zp
{
    LL cnt,sum,squasum;
    zp()
    {
        cnt=-1;
        sum=0;
        squasum=0;
    }
} dp[30][10][10];
int x[100];
LL cf[100];
zp dfs(int len,int num,int mod,int flag)
{
    zp ans;
    ans.cnt=ans.squasum=ans.sum=0;//不要忘记这一步,应为出事化的cnt为-1if(len==-1)
    {
        zp w;
        w.cnt=(mod!=0&&num!=0);
        w.squasum=w.sum=0;
        return w;
    }
    if(!flag&&dp[len][num][mod].cnt!=-1) return dp[len][num][mod];
    int stop=flag?x[len]:9;
    for(int i=0; i<=stop; i++)
    {
        if(i==7)
            continue;
        zp temp=dfs(len-1,(num*10+i)%7,(mod+i)%7,flag&&i==stop);
        ans.cnt+=temp.cnt;
        ans.cnt%=Mod;
        LL o=i*cf[len]%Mod;
        ans.sum+=(o*temp.cnt%Mod+temp.sum)%Mod;
        ans.sum%=Mod;
        ans.squasum+=o*o%Mod*temp.cnt%Mod+temp.squasum%Mod+2*temp.sum%Mod*o%Mod;
        ans.squasum%=Mod;
    }
    if(!flag) dp[len][num][mod]=ans;
    return ans;
}
zp solve(LL n)
{
    int cont=0;
    memset(x,0,sizeof(x));
    while(n)
    {
        x[cont++]=n%10;
        n/=10;
    }
    return dfs(cont-1,0,0,1);
}
int main()
{
    cf[0]=1;
    for(int i=1; i<=20; i++)
        cf[i]=(cf[i-1]*10)%Mod;
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        LL n,m;
        cin>>n>>m;
        cout<<(solve(m).squasum%Mod-solve(n-1).squasum%Mod+Mod)%Mod<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值