【五校联考5day2】光棍

题意

给你t个区间,让你求这个区间之间中不满足这三个条件之一的数的平方和。
1. S是a的倍数。
2. S在十进制表示下的各项数字加起来是a的倍数。
3. S的某一位是a

数据范围

对于15%的数据, 0<=L<=R<=106,T=1
对于35%的数据, 0<=L<=R<=107,T=1
另外有25%的数据, A=2,L=10k,R=10v, k和v都是自然数。
对于100%的数据, 0<=L<=R<=1018,2<=A<=9,T<=100

分析

一看就明显的 dp ,考试后还是第一次听说这个东东,所以就恶补了一下数位 dp 。。
首先按照惯例,我们要设一个 f[i,same,mo,sum] 表示枚举到第i位数(从高到低),前面i位是否与右边界相同(为了方便统计答案),前面i位组成的数对 a 取模的数,前面i位各个位加起来的和对a取模的数,的方案。那么有了这个通常还要再设一个 g[i,same,mo,sum] 为这些数的和(为了方便统计后面的平方和),最后就是 s[i,same,mo,sum] 表示为这些数的平方和。

转移方程

转移很简单,我们先讨论f的转移:枚举第i+1位的数是多少ch,那么转移到第i+1位就是
f[i+1,sameand(bit[i+1]=ch),(mo10+ch)modA,(sum+ch)modA]+=f[i,same,mo,sum](ch<>a,same=1,ch<=bit[i+1])
g的转移也是类似的:
g[i+1,sameand(bit[i+1]=ch),(mo10+ch)modA,(sum+ch)modA]+=g[i,same,mo,sum]10+chf[i,same,mo,sum](ch<>a,same=1,ch<=bit[i+1])
s的转移麻烦一点:

我们可以这样理解:(设 ai 表示当前的满足条件的数,现在要加上ch)
(a110+ch)2+(a210+ch)2+(a310+ch)2......
(a12100+ch2+20cha1)+(a22100+ch2+20cha2)+(a32100+ch2+20cha3)......
合并 a1+a2+a3... -> g[i,same,mo,sum]
合并 a12+a22+a32.... -> s[i,same,mo,sum]
合并 ch2+ch2+ch2..... -> f[i,same,mo,sum]ch2
那么这样原式变成 s[i,same,mo,sum]100+f[i,same,mo,sum]ch2+g[i,same,mo,sum]ch20
所以转移方程为:
s[i+1,sameand(bit[i+1]=ch),(mo10+ch)modA,(sum+ch)modA]+=s[i,same,mo,sum]100+f[i,same,mo,sum]ch2+g[i,same,mo,sum]ch20(ch<>a,same=1,ch<=bit[i+1])
最后再统计 mo<>0,sum<>0 的s即可
时间复杂度: O(TlogR2103)
这样便可以很好的解决问题了。

代码:(我是顺推的,所以初始化有点猥琐。。)

const m=1000000007;
var
    g,f,s:array[0..20,0..1,0..9,0..9] of int64;
    i,t,a:longint;l,r:int64;
procedure vare(var x:int64);begin if x=-1 then x:=0;end;
procedure sets(var x:longint;y:longint);
begin x:=(x+y)mod m;end;
procedure sets(i,p,mo,sum,i1,p1,mo1,sum1,k:longint);
begin
    vare(f[i,p,mo,sum]);vare(g[i,p,mo,sum]);vare(s[i,p,mo,sum]);
    f[i,p,mo,sum]:=(f[i,p,mo,sum]+f[i1,p1,mo1,sum1])mod m;
    g[i,p,mo,sum]:=(100*g[i1,p1,mo1,sum1]+20*k*s[i1,p1,mo1,sum1]+k*k*f[i1,p1,mo1,sum1]+g[i,p,mo,sum])mod m;
    s[i,p,mo,sum]:=(s[i1,p1,mo1,sum1]*10+k*f[i1,p1,mo1,sum1]+s[i,p,mo,sum])mod m;
end;
function solve(x,y:int64):int64;
var i,j,mo,sum,ch,t,o,p:longint;bit,ti:array[0..100] of integer;ans:int64;
begin
    if x=0 then exit(0);
    fillchar(f,sizeof(f),255);
    fillchar(g,sizeof(g),255);
    fillchar(s,sizeof(s),255);
    o:=0;
    while x<>0 do begin
       inc(o);bit[o]:=x mod 10;x:=x div 10;
    end;for i:=1 to o do ti[i]:=bit[o-i+1];bit:=ti;
    for i:=0 to bit[1] do if y<>i then begin
        if i=bit[1] then t:=1 else t:=0;
        vare(g[1,t,i mod y,i mod y]);vare(f[1,t,i mod y,i mod y]);vare(s[1,t,i mod y,i mod y]);
        inc(g[1,t,i mod y,i mod y],i*i);
        inc(f[1,t,i mod y,i mod y],1);
        inc(s[1,t,i mod y,i mod y],i);
    end;
    for i:=1 to o-1 do
        for p:=0 to 1 do
            for ch:=0 to 9 do if (p=1)and(bit[i+1]<ch) then break
            else begin
                if ch=y then continue;
                for mo:=0 to y do
                    for sum:=0 to y do begin
                        if f[i,p,mo,sum]=-1 then continue;
                        if (p=1)and(ch=bit[i+1]) then t:=1 else t:=0;
                        if ch=5 then
                           o:=o;
                        sets(i+1,t,(mo*10+ch)mod y,(sum+ch)mod y,i,p,mo,sum,ch);
                    end;
            end;ans:=0;
    for p:=0 to 1 do
            for mo:=0 to y do
                for sum:=0 to y do
                if (g[o,p,mo,sum]<>-1)and(sum<>0)and(mo<>0) then
                ans:=(ans+g[o,p,mo,sum])mod m;
    exit(ans);
end;
begin
    readln(t);
    for t:=1 to t do begin
        readln(l,r,a);
        writeln((solve(r,a)-solve(l-1,a)+m)mod m);
    end;
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值