题解 [HNOI2016]大数
题目大意
给出一个\(n\)个数的字符串,有\(m\)次查询,对于该串的子串\([l,r]\)有多少个子串满足是固定素数\(p\)的倍数。
思路
其实很简单,但是一开始想偏了。。。果然还是自己菜啊。。。
我们可以想到统计一下后缀和\(s[i]\),表示\([i,n]\)构成的数,那么,判断一个区间\([l,r]\)是不是\(p\)的倍数就等价于:
\]
我们发现如果\(\gcd(10,p)=1\)的话,分母就不会产生影响,于是判断条件就是:
\]
于是对于这种情况我们就可以用莫队\(\Theta(n\sqrt n)\)开桶记录答案。
如果\(\gcd(10,p)\not=1\)的话,那么\(p=2 \operatorname{or} 5\),我们发现这种情况对于区间\([l,r]\)判断是否的话直接判断第\(r\)位是不是\(2\operatorname{or}5\)的倍数即可。于是我们可以\(\Theta(n)\)解决这种情况。
果然还是自己菜了啊。。。这都没有看出来。。。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define ll long long
#define MAXN 200005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
char S[MAXN];
ll sum,ans[MAXN];int n,m,p,un,s[MAXN],tmp[MAXN],bel[MAXN],cnt[MAXN];
namespace Subtask1{
struct node{
int l,r,id;
bool operator < (const node &p)const{return bel[l] != bel[p.l] ? l < p.l : r < p.r;}
}q[MAXN];
void cge (int x,int k){sum -= 1ll * cnt[x] * (cnt[x] - 1) / 2,cnt[x] += k,sum += 1ll * cnt[x] * (cnt[x] - 1) / 2;}
void Work (){
int siz = sqrt (n);
for (Int i = n,c = 1;i;-- i,c = 1ll * c * 10 % p) s[i] = (s[i + 1] + 1ll * c * (S[i] - '0') % p) % p,bel[i] = (i - 1) / siz + 1,tmp[i] = s[i];
sort (tmp + 1,tmp + n + 2);un = unique (tmp + 1,tmp + n + 2) - tmp - 1;for (Int i = 1;i <= n + 1;++ i) s[i] = lower_bound (tmp + 1,tmp + un + 1,s[i]) - tmp;
read (m);for (Int i = 1;i <= m;++ i) read (q[i].l,q[i].r),q[i].r ++,q[i].id = i;sort (q + 1,q + m + 1);int l = 1,r = 0;
for (Int i = 1;i <= m;++ i){
while (l < q[i].l) cge (s[l ++],-1);while (l > q[i].l) cge (s[-- l],1);
while (r < q[i].r) cge (s[++ r],1);while (r > q[i].r) cge (s[r --],-1);
ans[q[i].id] = sum;
}
for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('\n');
return ;
}
}
namespace Subtask2{
int snum[MAXN];ll ssum[MAXN];
void Work(){
for (Int i = 1;i <= n;++ i){
snum[i] = ((S[i] - '0') % p == 0);
ssum[i] = ssum[i - 1] + 1ll * ((S[i] - '0') % p == 0) * i;
}
read (m);
while (m --){
int l,r;read (l,r);
write (ssum[r] - ssum[l - 1] - (snum[r] - snum[l - 1]) * (l - 1)),putchar ('\n');
}
}
}
signed main(){
read (p),scanf("%s",S + 1),n = strlen (S + 1);
if (p == 2 || p == 5) Subtask2::Work ();
else Subtask1::Work ();
return 0;
}
题解 [HNOI2016]大数的更多相关文章
- 【LG3245】[HNOI2016]大数
[LG3245][HNOI2016]大数 题面 洛谷 题解 60pts 拿vector记一下对于以每个位置为右端点符合要求子串的左端点, 则每次对于一个询问,扫一遍右端点在vector里面二分即可, ...
- 【BZOJ4542】[Hnoi2016]大数 莫队
[BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个 ...
- 4542: [Hnoi2016]大数
4542: [Hnoi2016]大数 链接 分析: 如果p等于2或者5,可以根据最后一位直接知道是不是p的倍数,所以直接记录一个前缀和即可. 如果p不是2或者5,那么一个区间是p的倍数,当且仅当$\f ...
- 题解-[HNOI2016]序列
题解-[HNOI2016]序列 [HNOI2016]序列 给定 \(n\) 和 \(m\) 以及序列 \(a\{n\}\).有 \(m\) 次询问,每次给定区间 \([l,r]\in[1,n]\),求 ...
- 4542: [Hnoi2016]大数
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
- BZOJ.4542.[HNOI2016]大数(莫队)
题目链接 大数除法是很麻烦的,考虑能不能将其条件化简 一段区间[l,r]|p,即num[l,r]|p,类似前缀,记后缀suf[i]表示[i,n]的这段区间代表的数字 于是有 suf[l]-suf[r+ ...
- 【bzoj4542】[Hnoi2016]大数 莫队算法
题目描述 给出一个数字串,多次询问一段区间有多少个子区间对应的数为P的倍数.其中P为质数. 输入 第一行一个整数:P.第二行一个串:S.第三行一个整数:M.接下来M行,每行两个整数 fr,to,表示对 ...
- [BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)
正经题解在最下面 http://blog.csdn.net/qq_32739495/article/details/51286548 写的时候看了大神的题解[就是上面那个网址],看到下面这段话 观察题 ...
- 洛谷P3245 [HNOI2016]大数 【莫队】
题目 题解 除了\(5\)和\(2\) 后缀数字对\(P\)取模意义下,两个位置相减如果为\(0\),那么对应子串即为\(P\)的倍数 只用对区间种相同数个数\(x\)贡献\({x \choose 2 ...
随机推荐
- Python 脚本的执行
源文件如下,文件名test.py,其中UTF-8根据实际情况而定,Python3默认为UTF-8,所以不用设置: #!/usr/bin/python # -*- coding: UTF-8 -*- p ...
- Dapper同时操作任意多张表的实现
1:Dapper的查询帮助类,部分代码,其它新增更新删除可以自行扩展 using Microsoft.Extensions.Configuration; using System; using Sys ...
- 01_Keil与Proteus联合仿真的注意事项
01. 关于keil5和Proteus8的联合仿真的操作步骤,这里就不细说,给个链接,步骤差不多是最齐全的 CSDN博客链接:https://blog.csdn.net/wzk456/article/ ...
- Django——Auth模块(用户认证模块)
1.Auth模块简介 auth模块是对登录认证方法的一种封装,之前我们获取用户输入的用户名及密码后需要自己从user表里查询有没有用户名和密码符合的对象. 而有了auth模块之后就可以很轻松的去验证用 ...
- 线程调用BeginInvoke
线程异步调用 Thread objThread = new Thread(new ThreadStart(delegate { Dispatch ...
- vim中字符串的替换
vi/vim 中可以使用 :s 命令来替换字符串 :s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky : ...
- windows中ren(rename-重命名)命令的使用方法
脚本(*.dat文件): cd /d %~dp0 ren * *.mp3
- eclipse安装配置
安装eclipse,并运行了第一个Hello World!
- POJ 2828 Buy Tickets(线段树单点)
https://vjudge.net/problem/POJ-2828 题目意思:有n个数,进行n次操作,每次操作有两个数pos, ans.pos的意思是把ans放到第pos 位置的后面,pos后面的 ...
- 学习PHP中国际化地数字格式处理
不知道大家有没有了解过,对于数字格式来说,西方国家会以三位为一个进位,使用逗号来分隔.比如,12345678,用标准的格式来表示的话就是 12,345,678 .不过我们中文其实并不会有这样的分隔符, ...