数数
这一道题给我们最大的启示就是一定要学会固定数字!下面要求的数组,如果按照数位DP的套路,从小到大考虑数位以及数位上的数字,是很容易想到需要求这些数组的
设
比如
我们求
那么此时的所以前缀为
此时我们再假设
然后我们再假设
以上过程完全可以先固定
设
然后试填的过程见以下代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const ll p=20130427;
int n,a[N];
ll f[N],g[N],h[N],Pow[N],B;
void prework()
{
f[0]=1;
Pow[0]=1;
for(int i=1;i<=N-10;i++)
{
Pow[i]=Pow[i-1]*B%p;
f[i]=(f[i-1]+Pow[i])%p;
h[i]=(((B-1)*B>>1)%p*f[i-1]%p*Pow[i-1]%p+B*h[i-1]%p)%p;
g[i]=(B*g[i-1]%p+h[i])%p;
}
}
ll work()
{
ll sum=0,val=0,res=0;
//sum表示已经填了的数字的所有子串的和
//val表示已经填了的数字的所有前缀子串的和
//rse表示结果
for(int i=n;i>=2;i--)
for(int j=1;j<B;j++)
{
res=(res+g[n-i]+h[n-i])%p;
res=(res+(j*Pow[n-i]%p*f[n-i]%p))%p;
}
//这个循环是在填写只有1位,2位...i-1位的情况
//注意不能直接填写最高位的0
//因为此时会导致重复计算
//比如n=3,数字为095
//那么本来应该只算9,5,95这三个子串的
//但如果直接从最高位的0开始算
//就会算成0,9,5,09,95,095
//显然重复了
for(int i=1;i<a[1];i++)
{
res=(res+g[n-1])%p;
res=(res+(i*Pow[n-1]%p*f[n-1]%p+h[n-1])%p)%p;
}
//考虑最高位的写法
val=a[1],sum=a[1];
for(int i=2;i<=n;i++)
{
for(int j=0;j<a[i];j++)
{
res=(res+g[n-i])%p;
ll temp=(val*B%p+(ll)j*i%p)%p;
res=(res+(temp*Pow[n-i]%p*f[n-i]%p+i*h[n-i])%p)%p;
res=(res+sum*Pow[n-i]%p)%p;
}
val=(val*B%p+(ll)a[i]*i%p)%p;
sum=(sum+val)%p;
}
//可以用博客讲的方法推一下上面代码的式子
return (res+sum)%p;
//注意还要在加上sum
//因为要计算这个数本身的贡献
}
int main()
{
scanf("%lld",&B);
prework();
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int j=n;
while(!a[j])
{
a[j]=B-1;
j--;
}
a[j]--;
if(j==1&&!a[j])
{
n--;
for(int i=1;i<=n;i++) a[i]=B-1;
}
ll res1=work();
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ll res2=work();
printf("%lld",(res2-res1+p)%p);
return 0;
}
以上代码肯定会超时,但是这个优化太简单了,具体见洛谷的提交
update 2024.9.17
重新做一遍,做出来了
其实我们走起来应该想的是求
但是注意,这道题目的模数不是质数,搞这个搞了好久。。纯诈骗,快速幂的幂的值就不是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2021-10-31 证明