HDU - 4507 恨7不成妻(数位dp**)

题目:求在一定区间内和7无关的数字的平方和。
  如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;

基本思想是(x+y)^2=x^2+2*x*y+y^2 维护sum和sqrt_sum,以及数量cnt来确定用了几次x^2。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
struct node{
    ll cnt;
    ll sum;
    ll sqsum;
};
int t,wei[20];
ll A,B,p[20];
node dp[20][10][10];

node dfs(int pos,int s1,int s2,int limit)
{
    if(pos<1)
    {
        node fuck;
        fuck.cnt=(s1!=0&&s2!=0);
        fuck.sum=fuck.sqsum=0;
        return fuck;
    }
    if(!limit&&dp[pos][s1][s2].cnt!=-1)
        return dp[pos][s1][s2];
    int up=limit?wei[pos]:9;
    node ans,tmp;
    ans.cnt=ans.sum=ans.sqsum=0;
    for(int i=0;i<=up;i++)
    {
        if(i==7)continue;
        tmp=dfs(pos-1,(s1+i)%7,(s2*10+i)%7,limit&&i==up);

        (ans.cnt+=tmp.cnt)%=mod;
        (ans.sum+=tmp.sum+tmp.cnt*i%mod*p[pos]%mod)%=mod;

        (ans.sqsum+=2ll*i*p[pos]%mod*tmp.sum%mod)%=mod;//求2xy
        (ans.sqsum+=1ll*i*i%mod*p[pos]%mod*p[pos]%mod*tmp.cnt%mod+tmp.sqsum)%mod;//x^2+y^2
    }
    if(!limit)dp[pos][s1][s2]=ans;
    return ans;
}

ll solve(ll x)
{
    int len=0;
    while(x)
    {
        wei[++len]=x%10;
        x/=10;
    }
    node ans=dfs(len,0,0,1);
    return ans.sqsum;
}
void init()
{
    for(int i=0;i<20;i++)
        for(int j=0;j<10;j++)
            for(int k=0;k<10;k++)
            dp[i][j][k].cnt=-1;
    p[1]=1ll;
    for(int i=2;i<20;i++)
        p[i]=p[i-1]*10ll%mod;
}
int main()
{
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&A,&B);
        ll ans=(solve(B)-solve(A-1)+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpXFire/article/details/81179060