题解 [51nod1607] 卷积和
解析
神仙LZF随机找出的毒瘤题.
一开始读题过于草率导致\(naive\)了.
step 1
看上去特别像数位DP(实际上也有一点).
先预处理出有\(i\)位的数(最高位不为\(0\))的数的变换值的和\(f[i]\),
它可以通过一段数前后各拼上一个数得到(也就是通过\(f[i-2]\)转化).
再设\(g[i]\)表示最高位可以为\(0\)的和,
那么\(f[i]=(g[i-2]*90+90*45*jc[i-2])\),
$g[i]=g[i-2]100+9045*jc[i-2] $,
(其中\(jc[i]\)代表\(10^i\)不要问为什么叫这个名字)
这里解释一下,
首先中间的一段在前后的0~9每个数字都加了一次,
所以一共加了100次,但由于\(f\)的最高位不为0所以是90次.
然后当前后的数字固定后中间的每个排列都要算上所以要乘上\(10^i\),
最后前后两端的数的和就是\(\sum_{i=0}^{9}\sum_{j=0}^{9}i*j+j*i\),
也就是\(45*45*2\).
step 2
我们可以把题目转化为求\(\sum_{i=1}^{i=r}f[i]-\sum_{i=1}^{i=l-1}f[i],\)
用前缀和的方式把问题分成两个相同的部分.
我们设那一整块为\(find(x)\),
设\(x\)有\(l\)位,
那前面的\(l-1\)位的数就直接预处理出来了:\(\sum_{i=1}^{l-1}f[i]\).
关键就在于处理\(l\)位的数.
这里我们拿\(56789\)举个例子,
预处理的话就到了\(9999\),
然后枚举每一位的数,
设第\(i\)位的数为\(a[i]\)(从低位到高位依次为1~\(l\)).
那么从0(最高位是1)到\(a[i]-1\)时,后面的数都可以随便取,
在例子里面就分别可以到\(49999,5999,699,89,8\).
然后我们就发现再加上它本身就把所有情况找齐了!
于是我们对每一位进行统计就行了.
step 3
现在我们来考虑怎么统计.
假设我们现在在统计第\(p\)位,
枚举每一位\(j\),以及它对应的\(k=l-j+1\).
那么对于\(j(k)\),它们有三种情况:大于\(p\),等于\(p\),小于\(p\).
当大于\(p\)时,它能贡献的就只有它那位上的数字,
其它的要么不能贡献要么在前面已经统计过了.
但是它贡献了0~\(a[p]-1\)次.
当等于\(p\)时,它就贡献了1~\(a[p]-1\)每个一次.
当小于\(p\)时,它就可以取0~9.
**注意,因为\(p\)后面的数可以随便取,所以还要在每次计算后面乘上\(10^t\),\(t\)取决于\(j,k\)的位置.
大概就这么多了...(具体的分类写在代码里了).
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std;
inline ll read(){
ll sum=0,f=1;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return f*sum;
}
const int N=101;
const int Mod=1000000007;
ll l,r;
ll f[N],g[N],a[N],jc[N];
inline ll find(ll x){
int len=0;ll ret=0;
for(;x;x/=10) a[++len]=x%10;
for(int i=1;i<len;i++) ret=(ret+f[i])%Mod;
for(int p=len;p;p--){
int nm=p-1,st=p==len? 1:0;//最高位不能为0
int tmp=0,tem=0,tt=a[p]-st;
for(int i=st;i<a[p];i++) tem+=i,tmp+=i*i;
//这里说一下因为长度可能为单数,所以有自己乘自己的情况,所以有tmp
for(int j=len;j;j--){
int k=len-j+1;
if(j>p){
if(k>p) ret=(ret+a[j]*a[k]*jc[nm]*tt)%Mod;//都大于p贡献了a[p]-st次
else if(k==p) ret=(ret+a[j]*tem*jc[nm])%Mod;//等于p贡献了st~a[p]每个一次
else ret=(ret+a[j]*45*jc[nm-1]*tt)%Mod;//因为k已经随便取了所以只有nm-1个数了
}
else if(j==p){
if(k>p) ret=(ret+tem*a[k]*jc[nm])%Mod;
else if(k==p) ret=(ret+tmp*jc[nm])%Mod;
else ret=(ret+tem*45*jc[nm-1])%Mod;
}
else{
if(k>p) ret=(ret+a[k]*45*jc[nm-1]*tt)%Mod;
else if(k==p) ret=(ret+45*tem*jc[nm-1])%Mod;
else{
if(k==j) ret=(ret+285*jc[nm-1]*tt)%Mod;//自己乘自己
else ret=(ret+45*45*jc[nm-2]*tt)%Mod;
}
}
}
}
for(int i=1;i<=len;i++) ret=(ret+a[i]*a[len-i+1])%Mod;
return ret;
}
signed main(){
l=read();r=read();
f[1]=g[1]=285;jc[0]=1;
for(int i=1;i<=19;i++) jc[i]=jc[i-1]*10%Mod;
for(int i=2;i<=19;i++){
f[i]=(g[i-2]*90%Mod+90*45*jc[i-2]%Mod)%Mod;
g[i]=(g[i-2]*100%Mod+90*45*jc[i-2]%Mod)%Mod;
}
printf("%lld\n",(find(r)-find(l-1)+Mod)%Mod);
return 0;
}
原文地址:https://www.cnblogs.com/zsq259/p/11425120.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 一天一大 lee(组合)难度:中等-Day20200908
- es6学习笔记
- 一天一大 lee(图像渲染)难度:简单-Day20200816
- 一天一大 lee(前 K 个高频元素)难度:中等-Day20200907
- 一天一大 lee(二叉树的层次遍历 II)难度:简单-Day20200906
- 一天一大 lee(第k个排列)难度:中等-Day20200905
- 一天一大 lee(二叉树的所有路径)难度:简单-Day20200904
- 一天一大 lee(N 皇后)难度:困难-Day20200903
- 一天一大 lee(二叉树的中序遍历)难度:中等-Day20200914
- 一天一大 lee(二叉树的层平均值)难度:简单-Day20200912
- 一天一大 lee(组合总和 II)难度:中等-Day20200910
- 一天一大 lee(组合总和 III)难度:中等-Day20200911
- 一天一大 lee(翻转二叉树)难度:简单-Day20200916
- 一天一大 lee(表示数值的字符串)难度:中等-Day20200902
- 一天一大 lee(单词搜索)难度:简单-Day20200913