HDU - 4507 吉哥系列故事——恨7不成妻(数位DP求平方和)

该博客主要解析了HDU 4507题目——恨7不成妻。通过数位DP方法,分析如何计算在特定区间内与7无关的数字的平方和。博主详细阐述了如何处理数位DP的状态转移,包括计算符合条件的数的个数、和以及平方和,提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:HDU - 4507 吉哥系列故事——恨7不成妻

题意:

如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;

现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。



分析:

设数位为: d l e n − 1 d l e n − 2 ⋯ d 2 d 1 d 0 d_{len-1}d_{len-2}\cdots d_2d_1d_0 dlen1dlen2d2d1d0

  • 常规的数位DP过程,可以处理出 d p [ i ] [ ⋯   ] . c n t dp[i][\cdots].cnt dp[i][].cnt i + 1 i+1 i+1位符合条件的数的个数

  • 先考虑处理出 d p [ i ] [ ⋯   ] . s u m dp[i][\cdots].sum dp[i][].sum i + 1 i+1 i+1位符合条件的数的和

设当前位(第i+1位)填入的数为 k k k,数位状态为: a b ⋯ k d i − 1 d i − 2 ⋯ d 2 d 1 d 0 ab\cdots kd_{i-1}d_{i-2}\cdots d_2d_1d_0 abkdi1di2d2d1d0

对于后 i + 1 i+1 i+1位,可拆分为: k ∗ 1 0 i + d i − 1 d i − 2 ⋯ d 2 d 1 d 0 k*10^i+d_{i-1}d_{i-2}\cdots d_2d_1d_0 k10i+di1di2d2d1d0

对其求和得:
k ∗ 1 0 i ∗ d p [ i − 1 ] [ ⋯   ] . c n t + d p [ i − 1 ] [ ⋯   ] . s u m k*10^i*dp[i-1][\cdots].cnt+dp[i-1][\cdots].sum k10idp[i1][].cnt+dp[i1][].sum

则有:
d p [ i ] [ ⋯   ] . s u m = ∑ k = 0 u p ( 上 式 ) dp[i][\cdots].sum=\displaystyle\sum_{k=0}^{up} (上式) dp[i][].sum=k=0up()



  • 最后处理 d p [ i ] [ ⋯   ] . s q s u m dp[i][\cdots].sqsum dp[i][].sqsum i + 1 i+1 i+1位符合条件的数的平方和

同样地,设当前位(第i+1位)填入的数为 k k k,数位状态为: a b ⋯ k d i − 1 d i − 2 ⋯ d 2 d 1 d 0 ab\cdots kd_{i-1}d_{i-2}\cdots d_2d_1d_0 abkdi1di2d2d1d0

对于后 i + 1 i+1 i+1位,可拆分为 k ∗ 1 0 i + d i − 1 d i − 2 ⋯ d 2 d 1 d 0 k*10^i+d_{i-1}d_{i-2}\cdots d_2d_1d_0 k10i+di1di2d2d1d0

平方后得:
k 2 ∗ 1 0 2 i + 2 ∗ k ∗ 1 0 i ∗ d i − 1 d i − 2 ⋯ d 2 d 1 d 0 + ( d i − 1 d i − 2 ⋯ d 2 d 1 d 0 ) 2 k^2*10^{2i}+2*k*10^i*d_{i-1}d_{i-2}\cdots d_2d_1d_0+(d_{i-1}d_{i-2}\cdots d_2d_1d_0)^2 k2102i+2k10idi1di2d2d1d0+(di1di2d2d1d0)2

对其求和得:
k 2 ∗ 1 0 2 i ∗ d p [ i − 1 ] [ ⋯   ] . c n t + 2 ∗ k ∗ 1 0 i ∗ d p [ i − 1 ] [ ⋯   ] . s u m + d p [ i − 1 ] [ ⋯   ] . s q s u m k^2*10^{2i}*dp[i-1][\cdots].cnt+2*k*10^i*dp[i-1][\cdots].sum+dp[i-1][\cdots].sqsum k2102idp[i1][].cnt+2k10idp[i1][].sum+dp[i1][].sqsum

则有:
d p [ i ] [ ⋯   ] . s q s u m = ∑ k = 0 u p ( 上 式 ) dp[i][\cdots].sqsum=\displaystyle\sum_{k=0}^{up} (上式) dp[i][].sqsum=k=0up()



以下代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const int maxn=1e5+10;
LL qpow(LL a,LL b)
{
    LL res=1;
    while(b)
    {
        if(b&1)
            res=(res*a)%MOD;
        a=(a*a)%MOD;
        b>>=1;
    }
    return res;
}
struct Node
{
    LL cnt;
    LL sum;
    LL sqsum;
}dp[30][10][10];
int a[30];
Node DFS(int pos,int rem1,int rem2,bool limit)
{
    if(pos<0)
        return Node{(rem1&&rem2)?1:0,0,0};
    if(!limit&&dp[pos][rem1][rem2].cnt!=-1)
        return dp[pos][rem1][rem2];
    int up=limit?a[pos]:9;
    Node res={0,0,0};
    for(int i=0;i<=up;i++)
    {
        if(i==7)
            continue;
        Node temp=DFS(pos-1,(rem1+i)%7,(rem2*10+i)%7,limit&&i==up);
        res.cnt+=temp.cnt;
        res.cnt%=MOD;
        res.sum+=i*qpow(10,pos)%MOD*temp.cnt%MOD+temp.sum;
        res.sum%=MOD;
        res.sqsum+=(i*qpow(10,pos)%MOD)*(i*qpow(10,pos)%MOD)%MOD*temp.cnt%MOD+2*i*qpow(10,pos)%MOD*temp.sum%MOD+temp.sqsum;
        res.sqsum%=MOD;
    }
    if(!limit)
        dp[pos][rem1][rem2]=res;
    return res;
}
LL solve(LL x)
{
    for(int i=0;i<30;i++)
        for(int j=0;j<10;j++)
            for(int k=0;k<10;k++)
                dp[i][j][k]=Node{-1,0,0};
    int len=0;
    while(x)
    {
        a[len++]=x%10;
        x/=10;
    }
    return DFS(len-1,0,0,true).sqsum;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL L,R;
        scanf("%lld %lld",&L,&R);
        printf("%lld\n",(solve(R)-solve(L-1)+MOD)%MOD);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值