【HNOI2016】大数

题目链接

题目描述

小 B 有一个很大的数 $ S $,长度达到了 $ N $ 位;这个数可以看成是一个串,它可能有前导 $ 0 $,例如 00009312345 。小 B 还有一个素数 $ P $。

现在,小 B 提出了 $ M $ 个询问,每个询问求 $ S $ 的一个子串中有多少子串是 $ P $ 的倍数($ 0 $ 也是 $ P $ 的倍数)。例如 $ S $ 为 0077 时,其子串 007 有六个子串:0, 0, 7, 00, 07, 007;显然 0077 的子串 077 的六个子串都是素数 $ 7 $ 的倍数。

输入格式

第一行一个整数:$ P $。

第二行一个串:$ S $。

第三行一个整数:$ M $。

接下来 $ M $ 行,每行两个整数 $ \text{fr}, \text{to}$,表示对 $ S $ 的子串 \(S[\text{fr} \ldots \text {to}]\) 的一次询问。

注意:$ S $ 的最左端的数字的位置序号为 $ 1 $;例如 $ S $ 为 $ 213567 $,则 $ S[1] $ 为 $ 2 \(,\) S[1 \cdots 3] $为 $ 213 $。

输出格式

输出 $ M $ 行,每行一个整数,第 $ i $ 行是第 $ i $ 个询问的答案。

样例

样例输入

11
121121
3
1 6
1 5
1 4

样例输出

5
3
2

样例解释

第一个询问问的是整个串,满足条件的子串分别有:121121211211121121

数据范围与提示

对于所有的数据,$ N,M \leq 100000 \(,\) P $ 为素数。

参考题解

我们要求的是

\[\displaystyle
\begin{align}
ans&=\sum_{i=l}^r\sum_{j=i}^r [\sum_{k=i}^js_k\cdot 10^{j-k} ==0\ mod\ p]\\
&=\sum_{i=l}^r\sum_{j=i}^r10^{j}[\sum_{k=i}^js_k\cdot 10^{-k} ==0\ mod\ p]
\end{align}
\]

如果质数\(P\)不等于\(2\)或\(5\),那么\(10^j\)不可能等于\(0\),并且\(10^k\)是有逆元的。

我们设\(s_k\cdot 10^{-k}\)的前缀和为\(sum_k\),则我们要求的就是:

\[\displaystyle
\sum_{i=l}^r\sum_{j=i}^r[sum_j==sum_i]
\]

这就是一个经典的莫队问题。

类似的题还有【CQOI2018】 异或序列。

当\(P\)等于\(2\)或者\(5\)的时候,我们知道只需要判断一个字串的最后一位就可以了,所以很好做。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 200005 using namespace std;
inline ll Get() {ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} ll p;
char s[N];
int n,m;
int bel[N];
ll ans[N];
ll sum[N],d[N];
ll cnt[N];
const int blk=450;
struct query {
int l,r;
int id;
bool operator <(const query &a)const {
if(bel[l]!=bel[a.l]) return l<a.l;
return bel[l]&1?r<a.r:r>a.r;
}
}q[N]; ll ksm(ll t,ll x,ll mod) {
ll ans=1;
for(;x;x>>=1,t=t*t%mod)
if(x&1) ans=ans*t%mod;
return ans;
} ll now=0;
void add(int v) {
now+=cnt[sum[v]];
cnt[sum[v]]++;
} void del(int v) {
cnt[sum[v]]--;
now-=cnt[sum[v]];
} ll tot[N],size[N];
int main() {
p=Get();
scanf("%s",s+1);
n=strlen(s+1);
m=Get();
for(int i=1;i<=m;i++) {
q[i].l=Get()-1,q[i].r=Get();
q[i].id=i;
} if(p!=2&&p!=5) {
for(int i=0;i<=n;i++) bel[i]=i/blk+1;
sort(q+1,q+1+m);
d[++d[0]]=0;
ll inv10=ksm(10,p-2,p),t=inv10;
for(int i=1;i<=n;i++) {
sum[i]=(sum[i-1]+(s[i]-'0')*t)%p;
t=t*inv10%p;
d[++d[0]]=sum[i];
}
sort(d+1,d+1+d[0]);
int cc=unique(d+1,d+1+d[0])-d-1;
for(int i=0;i<=n;i++) sum[i]=lower_bound(d+1,d+1+cc,sum[i])-d; int l=0,r=-1;
for(int i=1;i<=m;i++) {
while(r<q[i].r) add(++r);
while(l>q[i].l) add(--l);
while(r>q[i].r) del(r--);
while(l<q[i].l) del(l++);
ans[q[i].id]=now;
}
for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
} else {
if(p==2) {
for(int i=1;i<=n;i++) {
tot[i]=tot[i-1];
size[i]=size[i-1];
if((s[i]-'0')%2==0) {
tot[i]+=i;
size[i]++;
}
}
} else {
for(int i=1;i<=n;i++) {
tot[i]=tot[i-1];
size[i]=size[i-1];
if((s[i]-'0')%5==0) {
tot[i]+=i;
size[i]++;
}
}
}
for(int i=1;i<=m;i++) {
cout<<(tot[q[i].r]-tot[q[i].l])-(size[q[i].r]-size[q[i].l])*q[i].l<<"\n";
}
}
return 0;
}

【HNOI2016】大数的更多相关文章

  1. 【LG3245】[HNOI2016]大数

    [LG3245][HNOI2016]大数 题面 洛谷 题解 60pts 拿vector记一下对于以每个位置为右端点符合要求子串的左端点, 则每次对于一个询问,扫一遍右端点在vector里面二分即可, ...

  2. 4542: [Hnoi2016]大数

    4542: [Hnoi2016]大数 链接 分析: 如果p等于2或者5,可以根据最后一位直接知道是不是p的倍数,所以直接记录一个前缀和即可. 如果p不是2或者5,那么一个区间是p的倍数,当且仅当$\f ...

  3. 【BZOJ4542】[Hnoi2016]大数 莫队

    [BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个 ...

  4. BZOJ.4542.[HNOI2016]大数(莫队)

    题目链接 大数除法是很麻烦的,考虑能不能将其条件化简 一段区间[l,r]|p,即num[l,r]|p,类似前缀,记后缀suf[i]表示[i,n]的这段区间代表的数字 于是有 suf[l]-suf[r+ ...

  5. BZOJ4542: [Hnoi2016]大数

    Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...

  6. 4542: [Hnoi2016]大数

    Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...

  7. [BZOJ4542] [Hnoi2016] 大数 (莫队)

    Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...

  8. [HNOI2016]大数

    题目描述 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的 ...

  9. bzoj 4542: [Hnoi2016]大数

    Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345 小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...

  10. 洛谷P3245 [HNOI2016]大数(莫队)

    题意 题目链接 Sol 莫队板子题.. 维护出每个位置开始的字符串\(mod P\)的结果,记为\(S_i\) 两个位置\(l, r\)满足条件当且仅当\(S_l - S_r = 0\),也就是\(S ...

随机推荐

  1. python学习笔记(二)、字符串操作

    该一系列python学习笔记都是根据<Python基础教程(第3版)>内容所记录整理的 1.字符串基本操作 所有标准序列操作(索引.切片.乘法.成员资格检查.长度.最小值和最大值)都适用于 ...

  2. codeM美团编程大赛初赛B轮D题(考验你的数学思维!)

    [编程题] 模 时间限制:1秒空间限制:32768K 给定四个正整数a,b,c,k,回答是否存在一个正整数n,使得a*n在k进制表示下的各位的数值之和模b为c.输入描述:第一行一个整数T(T < ...

  3. Hibernate入门(七)一对多入门案例

    一对多 场景模拟:用户(一)对订单(多) 1.建表 创建客户表,字段有:客户id,客户姓名,客户性别,客户年龄,客户年纪,客户电话. 创建订单表,字段有:订单编号,明细编号,客户编号(外键) DROP ...

  4. Stackoverflow每日问题 系列前言

    都是程序员,想必都对stackoverflow有一定的了解,这个网站是世界上最为活跃的编程知识的论坛网站,上面活跃着数以万计的大神.提问各种有意义有价值的问题,还有这些问题的详细的回答. 但是毕竟是国 ...

  5. 8张图让你一步步看清 async/await 和 promise 的执行顺序

    摘要: 面试必问 原文:8张图帮你一步步看清 async/await 和 promise 的执行顺序 作者:ziwei3749 Fundebug经授权转载,版权归原作者所有. 为什么写这篇文章? 说实 ...

  6. 小tips:JS数值之间的转换,JS中最大的Number是多少?,JS == 与 === 的区别

    JS数值之间的转换 Number(), parseInt(),parseFloat() Number()函数的转换规则如下: 1.如果boolean值,true和false将分别被转换为1和02.如果 ...

  7. [工具配置]使用requirejs模块化开发多页面一个入口js的使用方式

    描述 知道requirejs的都知道,每一个页面需要进行模块化开发都得有一个入口js文件进行模块配置.但是现在就有一个很尴尬的问题,如果页面很多的话,那么这个data-main对应的入口文件就会很多. ...

  8. c#无边框窗体移动

    [DllImport("user32.dll")]//拖动无窗体的控件 public static extern bool ReleaseCapture(); [DllImport ...

  9. 配置多个相同网段的ECMP下一跳,配合NQA健康检查实现高可靠性

    1.一般情况下,ECMP常用的常见是,针对很远的目的地址,下一跳分别是路由器的不同出端口,而路由器的不同端口是不同网段的,也就是说,下一跳是不同的网段地址. 但是,在连接到终端服务器时,常常会采用多个 ...

  10. Android和H5进行数据交互,Android获取H5Input框中的内容

    项目中嵌入了H5 页面,这个时候就需要拿到H5 input中的内容进行数据传递,先看实现的效果图