随笔- 22  文章- 0  评论- 10  阅读- 1569 

恨 7不成妻

题目描述

什么样的数和 7 有关呢?如果一个整数符合下面三个条件之一,那么我们就说这个整数和 7 有关:
一. 整数中某一位是 7;
二. 整数的每一位加起来的和是 7 的整数倍;
三. 这个整数是 7 的整数倍。
现在问题来了:吉哥想知道在一定区间内和 7 无关的数字的平方和。

输入

输入数据的第一行是测试数据组数 T,然后接下来的 T 行表示 T 组测试数据。
每组数据在一行内包含两个正整数 L, R。

输出

对于每组数据,请计算 [L,R] 中和 7 无关的数字的平方和,并将结果对 109+7 取模后输出。

样例输入

3
1 9
10 11
17 17

样例输出

236
221
0

思路

用记搜解决。

第一点要求“整数中某一位是 7”,那么搜索过程中遇到7就剪枝;
第二点要求“整数的每一位加起来的和是 7 的整数倍”,则在搜索时记录前面各位数字之和%7的结果;
第三点要求“ 这个整数是 7 的整数倍”,则在搜索时记录前面的数%7的结果;

重点是答案要求的是平方和。

举个例子,假设求100~123的平方和

(100)2+(101)2+...+(123)2=(100)2+(100+1)2+...+(100+23)2=241002+2100(0+1+...+23)+02+12+...+232

因此,我们要想得到答案需要知道3个数:

要加的项数cnt(24)
下一层所有项的和sum1(0+1+...+23)
下一层所有项的平方和sum2(02+12+...+232)

因此需开一个结构体维护这三个数
再来看看如何从下一层的这三个数转移到该层
cnt:很简单,只需要每次把下层的累加上来就行了
sum1:可能有人会认为也只需累加就行,但其实不然,累加上来的只是(0+1+...+23),而我们想要的是(100+101+...+123)。所以我们需要在累加后再补上缺少的cnt个100
sum2:根据上面推出的式子,sum2应该=cnt1002+2100sum1+()sum2

100i10len(len)

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int digit[20];
const long long mm=1e9+7;
long long po[30];
struct node
{
    long long cnt,sum,squsum;
    node()
    {
        cnt=sum=squsum=0;
    }
};
node dp[20][20][20];
bool ok[20][20][20]={0};
node dfs(int len,int gsum,int mod,bool fp)//len:当前数的长度;gsum:前面各位数字之和%7的结果;mod:前面的数%7的结果;fp:是否到达顶端
{
    node ren;
    if (!len)
    {
        if(gsum&&mod)ren.cnt=1;//只有该数满足性质时才计数
        return ren;
    }
    if (!fp&&ok[len][gsum][mod])return dp[len][gsum][mod];//如果已经搜过就直接返回结果
    int fpmax=fp?digit[len]:9;
    node ret,cinn;
    for (int i=0;i<=fpmax;i++)
    {
        if(i==7)continue;
        cinn=dfs(len-1,(gsum+i)%7,(mod*10+i)%7,fp&&i==fpmax);
        ret.cnt=(ret.cnt+cinn.cnt)%mm;//累加cnt
        ret.sum=((ret.sum+cinn.sum)%mm+((cinn.cnt*i)%mm*po[len])%mm)%mm;//转移sum1
        ret.squsum=(ret.squsum+cinn.squsum)%mm;//转移sum2
        ret.squsum=(ret.squsum+(cinn.cnt*((po[len]*po[len])%mm*(i*i)%mm)%mm)%mm)%mm;
        ret.squsum=(ret.squsum+(2*(cinn.sum*po[len])%mm*i)%mm)%mm;
    }
    if(!fp){ok[len][gsum][mod]=1;dp[len][gsum][mod]=ret;}//记忆
    return ret;
}
int f(int n)
{
    int len = 0;
    while(n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    return (dfs(len,0,0,1).squsum)%mm;
}
signed main()
{
    int a,b,n;
    memset(dp,-1,sizeof(dp));
    po[1]=1;
    for(int i=2;i<=18;i++)
        po[i]=(po[i-1]*10)%mm;
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",(f(b)-f(a-1)+mm)%mm);
    }
    return 0;
}
 posted on   hu_led  阅读(24)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示