测试地址:数数
题目大意: 给定
两个
位内的
进制数,
,对区间
内的全部数
,累加
中全部子串表示的数字的和(如
,应该累加
到答案中,注意不该该包含前导零),求最终答案(用
进制表示)。
作法: 本题须要用到数位DP。
神题。虽然一眼能看出数位DP,但具体的转移式子仍是想错了好多回,此次终于写对了。
首先咱们来看,对于一个
位的数
,在它末尾加一位数
,会对这个数的全部子串表示的数字和有什么影响(如下简写成
)。令
表示数
全部后缀表示的数字和,那么有:
根据这个为基础,咱们就能思考数位DP的转移了。
根据套路,首先把问题转化为:用小于等于
的全部数的贡献,减去小于等于
的全部数的贡献,因而如今咱们考虑求小于等于某个数
时的贡献。
从高位向低位枚举,令
表示前
位中,不卡/卡上界的全部数的
的和,
表示前
位中,不卡/卡上界的全部数的
的和。先分析具体的转移过程:
前
位的数不卡上界时,第
位能够填
~
内全部的数,而且新的数都不卡上界;
前
位的数卡上界时,第
位能够填
~
。当填
~
时,新的数不卡上界,当填
时新的数卡上界。
因而咱们先考虑
的转移。首先,卡上界的状况应该很好转移了,实际上就是求上界的
值。主要是不卡上界的状况比较复杂。
首先考虑不卡上界转移到不卡上界的状况。根据上面的转移式子
,咱们这样考虑:首先枚举
从
到
,对于每个
,再枚举可转移的
,把贡献累加起来。因而一个
对整个
的贡献是:
,那么对于全部
,对
的贡献就是:
。其中
就是
,而
须要斟酌一下。这个和式是在求,对于全部可转移的
(包括
),累加它们的位数
(把
的位数看作
)。观察规律,咱们发现:
有
个,
有
个,
有
个,
有
个…
有
个,
有
个,
表示
的前
位组成的前缀。那么前面的有规律的部分能够递推维护,而
显然也能够递推维护,因此咱们就能够每次
地进行这个转移了。
接下来考虑卡上界转移到不卡上界的状况。这种状况下,能转移到不卡上界的状况,
必须是
~
,并且由于这种状况中可转移的
只有一个,并且
就是
,所以就比上面的状况简单不少了,总贡献应该为
。
那么
的转移讨论完了,接下来讨论
的转移。
就是求上界的
,而
也利用上面的思考方式,先考虑从不卡上界转移的状况,由于有
种转移,因此
就产生了
次的贡献。再考虑从卡上界转移的状况,由于有
种转移,因此
就产生了
次的贡献。再加上全部不卡上界数的后缀产生的贡献,即
,就能够计算出
了。
至此,通过漫长的讨论,咱们获得了一个
的数位DP,完美地解决了这一道题。
如下是本人代码:php
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=20130427; int n; ll s[100010],B,sum[100010][2],suf[100010][2]; ll pw[100010],num[100010],sumnum[100010]={0}; ll solve() { sum[0][0]=sum[0][1]=suf[0][0]=suf[0][1]=num[0]=0; for(int i=1;i<=n;i++) { if (i>2) sumnum[i]=(sumnum[i-1]+(ll)(i-1)*(B-1ll)%mod*pw[i-3]%mod)%mod; num[i]=(num[i-1]*B%mod+s[i])%mod; ll tmp=0; if (i>1) tmp=(sumnum[i]+1ll+(num[i-1]-pw[i-2]+mod)%mod*(ll)i%mod)%mod; suf[i][1]=(suf[i-1][1]*B%mod+s[i]*(ll)i%mod)%mod; suf[i][0]=(suf[i-1][0]*B%mod*B%mod+B*(B-1ll)/2ll%mod*tmp%mod)%mod; suf[i][0]=(suf[i][0]+suf[i-1][1]*B%mod*s[i]%mod+s[i]*(s[i]-1ll)/2ll%mod*(ll)i%mod)%mod; sum[i][1]=(sum[i-1][1]+suf[i][1])%mod; sum[i][0]=(sum[i-1][0]*B%mod+suf[i][0])%mod; sum[i][0]=(sum[i][0]+sum[i-1][1]*s[i]%mod)%mod; } return (sum[n][0]+sum[n][1])%mod; } int main() { ll ans; scanf("%lld",&B); scanf("%d",&n); pw[0]=1; for(int i=1;i<=n;i++) { scanf("%lld",&s[i]); pw[i]=pw[i-1]*B%mod; } ans=(mod-solve()+sum[n][1])%mod; scanf("%d",&n); pw[0]=1; for(int i=1;i<=n;i++) { scanf("%lld",&s[i]); pw[i]=pw[i-1]*B%mod; } ans=(ans+solve())%mod; printf("%lld",ans); return 0; }