题目

题目大意

给你一个区间\([l,r]\),求这个区间内每个整数的十进制上从高位到低位的逆序对个数之和。


思考历程

一开始就知道这是个数位DP……

结果一直都没有调出来,心态崩了……


正解

先讲讲我的SB做法。

先设\(f_i\)表示压着第\(i\)位(从低位到高位,从\(0\)开始)的贡献。

于是转移就是这样:

  1. 计算第\(i\)位的贡献。这一位的贡献可能有点难计算,所以我预处理了一个\(h_{i,j,0/1}\)表示是否压着\(i\)位,\(0\)到\(i\)位对\(j\)的贡献(\(j\)是\(i\)位之后的某个在\([0,9]\)之间的数)。那么这个东西就是\(h_{i,a_i}\)
  2. 从\(i-1\)位转移过来,其中\(i-1\)位也被压着。显然是\(f_{i-1}\)。
  3. 从\(i-1\)位转移过来,其中\(i-1\)位不被压着。枚举这一位选择\(x\),贡献就是\(\sum_{x=0}^{a_{i-1}-1}|x<j|*10^{i-1}+g_{i-2}+(i-1)*10^{i-2}x\)。\(g_i\)表示\(0\)位到\(i\)位任意选的方案数。这条式子可以化简,这里就不打出来了。

先考虑\(g\)怎么转移,显然是从前面转移过来并且加上这一位的贡献。

也就是\(g_i=10*g_{i-1}+\frac{(0+9)*10}{2}i*10^i\)

再考虑\(h\)的转移。

\(h_{i,j,0}=j*10^i+10*h_{i-1,j,0}\)

\(h_{i,j,1}\)的转移相对复杂一些。和\(f\)的转移有点类似。

记\(num\)为\(0\)到\(i-1\)位形成的十进制数,也就是整个数模\(10^i\)。

\(h_{i,j,1}=|a_i<j|*(num+1)+h_{i-1,j,1}+(\sum_{x=0}^{a_{i-1}-1}|x<j|*10^{i-1}+h_{i-2,j,0})\)

同样也可以化简一下。

化简后,很容易发现这样转移的时间复杂度是\(O(10n)\)的。

另外有个可能比较简单地比较高级的做法:

从高位到低位枚举一个\(i\),表示\(i\)位压着上限,然后记下此时的贡献。

那么贡献有三种:

  1. 高于\(i\)的位和\(i\)的贡献。由于\(i\)是压着上限的,所以前面所有数字的出现次数可以用一个桶记录下来。
  2. \(i\)位和低于\(i\)位的贡献。我们强制后面一位没有压着上限,因为后面那一位压着上限的方案数将会在后面计算到。枚举后面的一位,再后面的就可以随便选。
  3. 高于\(i\)位和低于\(i\)位的贡献。这个计算也跟上一个差不多。

然后就没了。


代码

这题是在是太恶心了……细节奇多无比……

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define mo 998244353
#define LEN 500010
#define ll long long
char str[LEN];
int n,m,L[LEN],R[LEN];
inline void read(int a[],int &n){
scanf("%s",str);
n=strlen(str);
for (int i=0;i<n;++i)
a[i]=str[n-i-1]-'0';
a[n]=0;
}
ll _pow10[LEN],*pow10=_pow10+1;
ll f[LEN],g[LEN],h[LEN][10][2];
inline ll get(int a[],int n){
if (n<=0)
return 0;
g[0]=0;
for (int i=1;i<=n;++i)
g[i]=(g[i-1]*10+45*i*pow10[i-1])%mo;
for (int j=0;j<=9;++j)
h[0][j][0]=j,h[0][j][1]=(a[0]<j);
for (int i=1,num=a[0];i<=n;num=(num+pow10[i]*a[i])%mo,++i)
for (int j=0;j<=9;++j){
h[i][j][0]=(h[i-1][j][0]*10+j*pow10[i])%mo;
int tmp=min(a[i-1],j);
h[i][j][1]=((a[i]<j?num+1:0)+h[i-1][j][1]+(i-2>=0?h[i-2][j][0]*a[i-1]:0)+tmp*pow10[i-1])%mo;
}
f[0]=0,f[1]=min(a[0]+1,a[1]);
for (int i=2;i<=n;++i)
f[i]=(h[i][a[i]][1]+f[i-1]+a[i-1]*g[i-2]+(i-1)*pow10[i-2]*((a[i-1]-1)*a[i-1]>>1))%mo;
return f[n];
}
int main(){
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
pow10[0]=1;
for (int i=1;i<=500001;++i)
pow10[i]=pow10[i-1]*10%mo;
int T,ty;
scanf("%d%d",&T,&ty);
while (T--){
read(L,n),read(R,m);
L[0]--;
for (int i=0;L[i]<0;++i)
L[i+1]--,L[i]+=10;
if (!L[n-1])
n--;
printf("%lld\n",(get(R,m)-get(L,n)+mo)%mo);
}
return 0;
}

总结

其实这题思维上是不难的……

只是过程实在太烦……

6361. 【NOIP2019模拟2019.9.18】鲳数的更多相关文章

  1. 6362. 【NOIP2019模拟2019.9.18】数星星

    题目描述 题解 一种好想/好写/跑得比**记者还快的做法: 对所有询问排序,按照R递增的顺序来处理 维护每个点最后一次被覆盖的时间,显然当前右端点为R时的答案为所有时间≥L的点的权值之和 LCT随便覆 ...

  2. jzoj6009. 【THUWC2019模拟2019.1.18】Counting (dp)

    Description 羽月最近发现,她发动能力的过程是这样的: 构建一个 V 个点的有向图 G,初始为没有任何边,接下来羽月在脑中构建出一个长度为 E 的边的序列,序列中元素两两不同,然后羽月将这些 ...

  3. 6392. 【NOIP2019模拟2019.10.26】僵尸

    题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...

  4. 6389. 【NOIP2019模拟2019.10.26】小w学图论

    题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...

  5. 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]

    题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...

  6. 【NOIP2019模拟2019.10.07】果实摘取 (约瑟夫环、Mobius反演、类欧、Stern-Brocot Tree)

    Description: 小 D 的家门口有一片果树林,果树上果实成熟了,小 D 想要摘下它们. 为了便于描述问题,我们假设小 D 的家在二维平面上的 (0, 0) 点,所有坐标范围的绝对值不超过 N ...

  7. 6371. 【NOIP2019模拟2019.9.28】基础图论练习题

    题目 题目大意 维护一个无向图的割边条数,支持加边和删边. 正解 (PS:这是我很久之前在OJ上打出来的题解,现在直接copy过来) 题解只有一句话,估计没多少人可以看得懂.感觉出题人偷懒不想写题解- ...

  8. 6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]

    题目 题目大意 给你一个数列,每次可以选择任意两个相邻的数\(x\)和\(y\),将其删去,并在原来位置插入\(x+2y\). 每次询问一个区间,对这个区间进行上述操作.求最后剩下的数最大是多少. 答 ...

  9. NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)

    传送门. 题解: 我果然是不擅长分类讨论,心态被搞崩了. 注意到\(m<=n-2\),意味着除了1以外的位置不可能被加到a[1]两遍. 先考虑个大概: 考虑若存在\(x,x-1,-,2\)(有序 ...

随机推荐

  1. linux 命令 - man, help, info(查看命令帮助手册)

    man, help, info - 查看命令帮助手册   help xxx  # 显示内置命令帮助信息: xxx --help  # 显示外置命令帮助信息: man xxx  # 没有内建与外部命令的 ...

  2. 前端学习(十二)js数据类型(笔记)

    选项卡:        for循环 for(初始值,条件,自增){}    for(var i=0; i<9;i++){} 几个按钮对应相同个内容!!! -------------------- ...

  3. asp.net网站Application_Start疑是不执行的现象

    今天遇见了一个很诡异的事情,发布了新代码后,发现在Application_Start中读取的一些配置参数变为空了,最开始我以为是什么特殊的原因程序没有执行Application_Start,导致它们的 ...

  4. js取整 - 优雅版(装逼必备)

    var a = 2.98; var z1 = ~~a; var z2 = a | 0; var z3 = a>>0; console.log(z1, z2, z3);     // 2, ...

  5. nodejs模块——fs模块 读取文件

    readFile读取文件 fs.readFile(filename,[option],callback) 方法读取文件. 参数说明: filename String 文件名 option Object ...

  6. jedate(日期插件)

    首先要引入JQuery,然后引入jedate.css和jedate.js(注:需要把下载好的jedate文件夹整个的放在项目中,不然图标无法显示) 没有把整个文件夹放进去的效果            ...

  7. Python 项目隔离环境virtualenv--venv

    virtualenv 用来为一个应用创建一套“隔离”的python运行环境. 先安装virtualenv: pip3 install virtualenv 再进入项目目录,或者创建一个项目目录并进入, ...

  8. 「ZJOI2019」线段树 解题报告

    「ZJOI2019」线段树 听说有人喷这个题简单,然后我就跑去做,然后自闭感++,rp++(雾) 理性分析一波,可以发现最后形成的\(2^k\)个线段树,对应的操作的一个子集,按时间顺序作用到这颗线段 ...

  9. iOS: NSTimer使用小记

    目录 1. NSRunLoopCommonModes和Timer 2. NSThread和Timer 3. GCD中的Timer 返回目录 1. NSRunLoopCommonModes和Timer ...

  10. 【系统安全性】二、Web攻击与防范

    二.Web攻击与防范 1.XSS攻击 跨站脚本攻击(Cross Site Scripting),因为简写CSS,与层叠样式表(Cascading Style Sheets)有歧义,所以取名XSS 原理 ...