【HNOI2016】大数
【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
样例解释
第一个询问问的是整个串,满足条件的子串分别有:121121、2112、11、121、121。
数据范围与提示
对于所有的数据,$ N,M \leq 100000 \(,\) P $ 为素数。
我们要求的是
\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\),则我们要求的就是:
\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】大数的更多相关文章
- 【LG3245】[HNOI2016]大数
		
[LG3245][HNOI2016]大数 题面 洛谷 题解 60pts 拿vector记一下对于以每个位置为右端点符合要求子串的左端点, 则每次对于一个询问,扫一遍右端点在vector里面二分即可, ...
 - 4542: [Hnoi2016]大数
		
4542: [Hnoi2016]大数 链接 分析: 如果p等于2或者5,可以根据最后一位直接知道是不是p的倍数,所以直接记录一个前缀和即可. 如果p不是2或者5,那么一个区间是p的倍数,当且仅当$\f ...
 - 【BZOJ4542】[Hnoi2016]大数 莫队
		
[BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个 ...
 - BZOJ.4542.[HNOI2016]大数(莫队)
		
题目链接 大数除法是很麻烦的,考虑能不能将其条件化简 一段区间[l,r]|p,即num[l,r]|p,类似前缀,记后缀suf[i]表示[i,n]的这段区间代表的数字 于是有 suf[l]-suf[r+ ...
 - BZOJ4542: [Hnoi2016]大数
		
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
 - 4542: [Hnoi2016]大数
		
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
 - [BZOJ4542] [Hnoi2016] 大数 (莫队)
		
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
 - [HNOI2016]大数
		
题目描述 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的 ...
 - bzoj 4542: [Hnoi2016]大数
		
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345 小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
 - 洛谷P3245 [HNOI2016]大数(莫队)
		
题意 题目链接 Sol 莫队板子题.. 维护出每个位置开始的字符串\(mod P\)的结果,记为\(S_i\) 两个位置\(l, r\)满足条件当且仅当\(S_l - S_r = 0\),也就是\(S ...
 
随机推荐
- SQL Server远程连接 provider: Named Pipes Provider, error: 40 解决方法
			
置SQLServer,允许远程连接 按照上面的文章一步步配置后,远程连接出现下面所示的报错(Navicat 和 SQL Server Management Studio) SQL Server Man ...
 - 【Java】Properties文件的解析
			
public abstract class ReadProperties { public ReadProperties() {} /** * 回调函数,由调用者处理 * @param key * @ ...
 - vim 学习笔记系列(前言)
			
今天上午的时候,看到大神在用vim编程,画面直观,速度很快,操作只需要用命令符就可以实施. 所以可以推断vim的命令符是复杂的,那么学习过程中记忆会很漫长,很痛苦,但是如果记住了这些命令符,并可以熟练 ...
 - 有哪些Java性能优化方法?
			
面试官:"有性能优化经验没?" 应聘者:"有一点." 面试官:"那你们从哪些方面做了优化?" 应聘者:"sql优化.JV ...
 - h5网页水印SDK的实现代码示例
			
在网站浏览中,常常需要网页水印,以便防止用户截图或录屏暴露敏感信息后,追踪用户来源.如我们常用的钉钉软件,聊天背景就会有你的名字.那么如何实现网页水印效果呢? 网页水印SDK,实现思路 1.能更具获取 ...
 - jQuery效果之jQuery Color animation 色彩动画扩展
			
jQuery 的动画方法(animate)支持各种属性的过渡,但是默认并不支持色彩的过渡,该插件正是来补足这一点! PS: 该插件支持 RGBA 颜色的过渡,但是请注意,IE8以下的版本不支持 RGB ...
 - vue+vuecli+webpack中使用mockjs模拟后端数据
			
前言 使用mockjs可以事先模拟数据,前提是和后端约定好了数据接口,怎样的数据.使用mock就可以生成你要的数据了,从而实现开发时前后端分离. 其主要功能是: 基于数据模板生成模拟数据. 基于HTM ...
 - Vue2+VueRouter2+webpack 构建项目实战(三):配置路由,运行页面
			
制作.vue模板文件 通过前面的两篇博文的学习,我们已经建立好了一个项目.问题是,我们还没有开始制作页面.下面,我们要来做页面了. 我们还是利用 http://cnodejs.org/api 这里公开 ...
 - writing objects : 值%停住
			
在git bush 中使用命令:git config --global http.postBuffer 524288000 因为git上传,限定一次push命令的buffer大小.
 - error 2593 operator << 不明确的可能的解决方法
			
编译Martinez算法时遇到该问题,提示重载的<<操作符调用不明确. 解决方法为:在cpp文件中将重载的该操作符的实现前添加完整的命名空间路径.