Processing math: 100%

HUD 4507 吉哥系列故事——恨7不成妻

传送门

三个限制都可以数位 dpdfs 是维护当前位,之前各位总和模 7 意义下的值,之前填的数模 7 意义下的值,是否贴着限制

主要现在求的是各个合法数的平方的和,比较恶心

开一个结构体维护一下三个东西,合法数的个数,合法数的和,合法数的平方和

前两个好维护,平方和发现其实可以拆开,比如下一层 dfs 传上来的和为 x ,当前位填的数为 k ,考虑当前所有合法数的平方和看成每一个合法数的平方的和

设下一层某一个合法数传上来的值为 y,那么当前层的值即为

10pk+y ,平方后即为 102pk2+y2+2ky10p

发现所有的 y2 加起来以后其实就是下一层的合法数的平方和

对于 2ky10p ,把 2k10p 提出来,那么也可以把所有 y 加起来即为下一层的合法数的和

对于 102pk2 ,因为加了下一层合法数的个数次,那么贡献即为下一层合法数数量乘 102pk2

所以我们完全可以用下一层的数据维护出当前位的数据

具体实现可以看代码

 

复制代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int mo=1e9+7;
inline int fk(int x) { return x>=mo ? x-mo : x; }
ll T,L,R;
struct dat {
    ll tot,sum,sum2;
    dat (ll _tot=0,ll _sum=0,ll _sum2=0) { tot=_tot,sum=_sum,sum2=_sum2; }
    inline dat operator + (const dat &tmp) const {
        return dat(fk(tot+tmp.tot),fk(sum+tmp.sum),fk(sum2+tmp.sum2));
    }
    inline dat operator * (const ll &tmp) const {
        return dat(tot, fk(tot*tmp%mo + sum) , fk( fk((tot*tmp%mo)*tmp%mo + (2ll*tmp%mo)*sum%mo) + sum2 ) );
    }
}f[19][9][9][2];
ll Power[19];
vector <int> V;
dat dfs(int p,int sum,int now,bool lim)
{
    if(!p) return (sum&&now) ? dat(1,0,0) : dat(0,0,0);
    dat &t=f[p][sum][now][lim];
    if(t.tot!=-1) return t;
    t.tot=0;
    for(int k=0;k<=9;k++)
    {
        if(lim&&k>V[p-1]) break;
        if(k==7) continue;
        dat add=dfs(p-1,(sum+k)%7,(now*10+k)%7,lim&(k==V[p-1]));
        t=t + ( add * (Power[p-1]*k%mo) );
    }
    // cout<<p<<" "<<sum<<" "<<now<<" "<<lim<<" "<<t.tot<<" "<<t.sum<<" "<<t.sum2<<endl;
    return t;
}
inline void Clr()
{
    for(int i=1;i<=18;i++)
        for(int j=0;j<7;j++)
            for(int k=0;k<7;k++)
                f[i][j][k][0]=f[i][j][k][1]=dat(-1,0,0);
}
int main()
{
    T=read();
    Power[0]=1; for(int i=1;i<=18;i++) Power[i]=Power[i-1]*10%mo;
    while(T--)
    {
        L=read()-1,R=read();
        ll now=R; V.clear(); Clr();
        while(now) V.push_back(now%10),now/=10;
        ll ans=dfs(V.size(),0,0,1).sum2;
        now=L; V.clear(); Clr();
        while(now) V.push_back(now%10),now/=10;
        printf("%d\n",fk(ans-dfs(V.size(),0,0,1).sum2+mo));
    }
    return 0;
}
复制代码

 

posted @   LLTYYC  阅读(168)  评论(0编辑  收藏  举报
编辑推荐:
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
阅读排行:
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 使用 Dify + LLM 构建精确任务处理应用
历史上的今天:
2018-10-16 P4363 [九省联考2018]一双木棋chess
点击右上角即可分享
微信分享提示