[HNOI 2016]大数
Description
给你一个长度为 \(n\) ,可含前导零的大数,以及一个质数 \(p\) 。 \(m\) 次询问,每次询问你一个大数的子区间 \([l,r]\) ,求出子区间中有多少个子串为 \(p\) 的倍数。
\(1\leq n,m\leq 100000\)
Solution
记 \(a_i\) 为大数第 \(i\) 位上的数值。
注意到题目是要求 \[\sum_{i=l}^r\sum_{j=i}^r\left[\sum_{k=i}^ja_k\cdot 10^{j-k}\equiv 0\pmod{p}\right]\]
我们可以将其等价变形 \[\Rightarrow\sum_{i=l}^r\sum_{j=i}^r\left[10^j\sum_{k=i}^ja_k\cdot 10^{-k}\equiv 0\pmod{p}\right]\]
由于 \(p\) 是质数,同时在 \(p\neq 2\wedge p\neq 5\) 时, \(\nexists i,10^i\equiv 0\pmod{p}\) ;且对于 \(\forall i,10^{-i}\) 存在逆元。
所以我们先讨论 \(p\neq 2\wedge p\neq 5\) 的情况。
我们不妨记 \(sum_i=\sum\limits_{j=1}^ia_j\cdot10^{-j}\) 在模 \(p\) 意义下的结果。
原式等价于 \[\begin{aligned}\Rightarrow&\sum_{i=l}^r\sum_{j=i}^r\left[\sum_{k=i}^ja_k\cdot 10^{-k}\equiv 0\pmod{p}\right]\\=&\sum_{i=l}^r\sum_{j=i}^r\left[sum_j-sum_{i-1}\equiv 0\pmod{p}\right]\\=&\sum_{i=l}^r\sum_{j=i}^r\left[sum_j=sum_{i-1}\right]\end{aligned}\]
发现这不就是莫队的板子么,求子区间内有多少数对相等。直接套板子就好了。
然后对于 \(p= 2\vee p= 5\) ,可以特判,讨论比较简单,不再赘述。
Code
注意这个代码是过不了的。但在 luogu 上强行开 O2 过了,就得过且过吧...
但是可以有这些优化:
- 优化莫队的计算过程,不用每次都算一遍组合数;
- 不用写 \(hash\) 表,直接排序离散化就好了
//It is made by Awson on 2018.2.11
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 200000;
const int MOD = 1e6+7;
void read(int &x) {
char ch; bool flag = 0;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
x *= 1-2*flag;
}
void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
int p, n, m, sum[N+5], inv, lim;
int tol[MOD+5];
char num[N+5];
LL ans[N+5];
namespace cheat2 {
struct bittree {
LL c[N+5];
void add(int x, int val) {for (; x <= n; x += lowbit(x)) c[x] += val; }
LL query(int x) {
LL sum = 0;
for (; x; x -= lowbit(x)) sum += c[x];
return sum;
}
}T;
int sum[N+5];
void main() {
scanf("%s", num+1); n = strlen(num+1);
for (int i = 1; i <= n; i++)
if ((num[i]-48)%2 == 0) T.add(i, i), sum[i] = sum[i-1]+1;
else sum[i] = sum[i-1];
read(m); int l, r;
while (m--) {
read(l), read(r); writeln(T.query(r)-T.query(l-1)-1ll*(sum[r]-sum[l-1])*(l-1));
}
}
}
namespace cheat5 {
struct bittree {
LL c[N+5];
void add(int x, int val) {for (; x <= n; x += lowbit(x)) c[x] += val; }
LL query(int x) {
LL sum = 0;
for (; x; x -= lowbit(x)) sum += c[x];
return sum;
}
}T;
int sum[N+5];
void main() {
scanf("%s", num+1); n = strlen(num+1);
for (int i = 1; i <= n; i++)
if ((num[i]-48)%5 == 0) T.add(i, i), sum[i] = sum[i-1]+1;
else sum[i] = sum[i-1];
read(m); int l, r;
while (m--) {
read(l), read(r); writeln(T.query(r)-T.query(l-1)-1ll*(sum[r]-sum[l-1])*(l-1));
}
}
}
struct HASH {
int k[MOD+5];
void clear() {memset(k, -1, sizeof(k)); }
void insert(int x) {
int loc = x%MOD;
while (true) {
if (k[loc] == -1 || k[loc] == x) {k[loc] = x; return; }
++loc; if (loc >= MOD) loc %= MOD;
}
}
int query(int x) {
int loc = x%MOD;
while (true) {
if (k[loc] == x) {return loc; }
++loc; if (loc >= MOD) loc %= MOD;
}
}
}mp;
struct tt {
int l, r, id;
bool operator < (const tt &b) const {return l/lim == b.l/lim ? r < b.r : l < b.l; }
}a[N+5];
int quick_pow(int a, int b, int p) {
int ans = 1;
while (b) {
if (b&1) ans = 1ll*ans*a%p;
b >>= 1, a = 1ll*a*a%p;
}
return ans;
}
LL C(int n) {return 1ll*n*(n-1)/2;}
void work() {
read(p); mp.clear();
if (p == 2) {cheat2::main(); return; }
if (p == 5) {cheat5::main(); return; }
inv = quick_pow(10, p-2, p); scanf("%s", num+1); n = strlen(num+1); lim = sqrt(n);
mp.insert(0);
for (int i = 1, j = inv; i <= n; i++, j = 1ll*j*inv%p) {
sum[i] = (sum[i-1]+1ll*(num[i]-48)*j%p)%p;
mp.insert(sum[i]);
}
read(m);
for (int i = 1; i <= m; i++) {read(a[i].l), --a[i].l, read(a[i].r), a[i].id = i; }
sort(a+1, a+m+1);
LL now = 0; int curl = 0, curr = 0; tol[mp.query(0)] = 1;
for (int i = 1; i <= m; i++) {
int l = a[i].l, r = a[i].r;
int id = mp.query(sum[curl]);
while (curl < l) now -= C(tol[id]), --tol[id], now += C(tol[id]), ++curl, id = mp.query(sum[curl]);
id = mp.query(sum[curl-1]);
while (curl > l) --curl, now -= C(tol[id]), ++tol[id], now += C(tol[id]), id = mp.query(sum[curl-1]);
id = mp.query(sum[curr+1]);
while (curr < r) ++curr, now -= C(tol[id]), ++tol[id], now += C(tol[id]), id = mp.query(sum[curr+1]);
id = mp.query(sum[curr]);
while (curr > r) now -= C(tol[id]), --tol[id], now += C(tol[id]), --curr, id = mp.query(sum[curr]);
ans[a[i].id] = now;
}
for (int i = 1; i <= m; i++) writeln(ans[i]);
}
int main() {
work(); return 0;
}
[HNOI 2016]大数的更多相关文章
- [HNOI 2016]树
Description 题库链接 给你一棵 \(N\) 个节点根节点为 \(1\) 的有根树,结点的编号为 \(1\sim N\) :我们称这颗树为模板树.需要通过这棵模板树来构建一颗大树.构建过程如 ...
- 【HNOI 2016】大数
Problem Description 小 B 有一个很大的数 \(S\),长度达到了 \(N\) 位:这个数可以看成是一个串,它可能有前导 \(0\),例如 00009312345 .小 B 还有一 ...
- 【BZOJ 4539】【HNOI 2016】树
http://www.lydsy.com/JudgeOnline/problem.php?id=4539 今天测试唯一会做的一道题. 按题目要求,如果暴力的把模板树往大树上仍,最后得到的大树是$O(n ...
- hnoi 2016 省选总结
感觉省选好难的说...反正我数据结构太垃圾正解想到了也打不出来打一打暴力就滚粗了! DAY1 0+20+30 DAY2 60-20+0+60 最后170-20分,暴力分还是没有拿全! 然而这次是给了5 ...
- HNOI 2016 省队集训日记
第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里. ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方, ...
- 数据结构(树链剖分,堆):HNOI 2016 network
2215. [HNOI2016]网络 ★★★☆ 输入文件:network_tenderRun.in 输出文件:network_tenderRun.out 简单对比时间限制:2 s 内存 ...
- [HNOI 2016]最小公倍数
Description 题库链接 给定一张 \(N\) 个顶点 \(M\) 条边的无向图(顶点编号为 \(1,2,\cdots,n\) ),每条边上带有权值.所有权值都可以分解成 \(2^a\time ...
- [HNOI 2016]序列
Description 题库链接 给你一个长度为 \(n\) 的序列 \(A\) ,给出 \(q\) 组询问.每次询问 \([l,r]\) ,求该区间内所有的子序列中最小值的和. \(1\leq n, ...
- [HNOI 2016]网络
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
随机推荐
- C作业--数据类型
一.PTA实验作业 题目1:7-3 倒顺数字串 1. 本题PTA提交列表 2. 设计思路(伪代码) (1)本题是要求输入倒顺序数串,首先看到这种题肯定是需要用到循环,那就先定一个整形i来进行循环,n是 ...
- JAVA_SE基础——6.标识符&关键字
学会写helloworld之后, 我们就开始来认识标识符&关键字 一.标识符 标识符是指可被用来为类.变量或方法等命名的字符序列,换言之,标识符就是用户自定义的名称来标识类.变量或方法等.更 ...
- 使用freemaker 导出word 含多张图片,若无图片则显示文本信息
1.使用的Microsoft Office 2007,添加一个无边框的表格,并插入一张图片,最后另存为编码utf-8,一开始保存的word xml格式的,图片的base64编码位于文档最后,暂时没有找 ...
- Vue2学习小记-给Vue2路由导航钩子和axios拦截器做个封装
1.写在前面 最近在学习Vue2,遇到有些页面请求数据需要用户登录权限.服务器响应不符预期的问题,但是总不能每个页面都做单独处理吧,于是想到axios提供了拦截器这个好东西,再于是就出现了本文. 2. ...
- Linux进程管理:后台启动进程和任务管理命令
一.为什么要使程序在后台执行 我们的应用有时候要运行时间很长,如:几个小时甚至几个星期,我们可以让程序在后台一直跑. 让程序在后台运行的好处有: 终端关机不影响后台进程的运行.(不会终端一关机或者网络 ...
- SpringCloud的EurekaClient : 客户端应用访问注册的微服务(无断路器场景)
演示客户端应用如何访问注册在EurekaServer里的微服务 一.概念和定义 采用Ribbon或Feign方式访问注册到EurekaServer中的微服务.1.Ribbon实现了客户端负载均衡,2. ...
- Couchbase忘记登录密码怎么办
以下都为root用户操作: 1.先关闭couchbase /opt/couchbase/etc/couchbase_init.d stop 2.切换到下面的路径,删除这个目录下除logs的所有文件,按 ...
- Mac里安装Jmeter
前提是需要安装jdk,参见http://www.cnblogs.com/fun0623/p/4703456.html 1.解压包 (双击apache-jmeter-2.13) 2.进去到解压后的bin ...
- Python中使用hashlib进行加密的简单使用
import hashlib ''' 原文= '字符串' 哈希加密对象 = hashlib.加密算法( 原文.encode('utf-8') ) 密文 = 哈希加密对象.hexdigest() #密文 ...
- hdu-2602&&POJ-3624---01背包裸题
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2602 https://vjudge.net/problem/POJ-3624 都是01背包的裸题 这 ...