列表

详情


NC20117. [HNOI2016]大数

描述

小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345 。
小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也 是P 的倍数)。
例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素数7的倍数。

输入描述

第一行一个整数:P。
第二行一个串:S。
第三行一个整数:M。
接下来M行,每行两个整数 fr,to,表示对S 的子串S[fr…to]的一次询问。
注意:S的最左端的数字的位置序号为 1;
例如S为213567,则S[1]为 2,S[1…3]为 213。N,M ≤ 100000,P为素数

输出描述

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

示例1

输入:

11 
121121 
3 
1 6 
1 5 
1 4

输出:

5
3
2

说明:

第一个询问问的是整个串,满足条件的子串分别有:121121,2112,11,121,121。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++ 11.0.1) 解法, 执行用时: 169ms, 内存消耗: 4560K, 提交时间: 2023-03-31 19:34:57

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <climits>
#define LL long long
using namespace std;
const int MAXN = 2e5 + 5;
int p, m, t, a[MAXN], lsh[MAXN], f, l = 1, r = 0, c[MAXN], n, pre[MAXN];
char s[MAXN];
LL ans[MAXN], res;
struct Node {
	int X, Y, pos;
	bool operator < (const Node P) const { return X / t != P.X / t ? X < P.X : Y < P.Y; }
}query[MAXN];
void Add(int x, int F) {
	if(f) c[a[x]] ++, F ? res += (a[x] % p == 0) * (r - l + 1) : res += c[a[x]];
	else res += c[pre[x]], c[pre[x]] ++; 
}
void Del(int x, int F) {
	if(f) F ? res -= (a[x] % p == 0) * (r - l + 1 + 1) : res -= c[a[x]], c[a[x]] --;
	else c[pre[x]] --, res -= c[pre[x]];
}
int main() {
	int qwq = 1;
	scanf("%d%s%d", &p, s + 1, &m); n = strlen(s + 1); t = sqrt(n);
	for(int i = 1; i <= n; i ++) a[i] = s[i] - '0';
	for(int i = n; i >= 1; i --) pre[i] = (LL)(pre[i + 1] + (LL)qwq * a[i]) % p, qwq = ((LL)qwq * 10) % p, lsh[i] = pre[i];
	for(int i = 1; i <= m; i ++) scanf("%d%d", &query[i].X, &query[i].Y), query[i].Y ++, query[i].pos = i;
	sort(query + 1, query + 1 + m);
	sort(lsh + 1, lsh + 2 + n);
	int len = unique(lsh + 1, lsh + 2 + n) - lsh - 1; 
	for(int i = 1; i <= n + 1; i ++) pre[i] = lower_bound(lsh + 1, lsh + 1 + len, pre[i]) - lsh;
	if(p == 2 || p == 5) f = 1;
	for(int i = 1; i <= m; i ++) {
		if(f) query[i].Y --;
		while(l < query[i].X) Del(l ++, 0);
		while(l > query[i].X) Add(-- l, 0);
		while(r < query[i].Y) Add(++ r, 1);
		while(r > query[i].Y) Del(r --, 1);
		ans[query[i].pos] = res;
	}
	for(int i = 1; i <= m; i ++) printf("%lld\n", ans[i]);
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 284ms, 内存消耗: 10208K, 提交时间: 2019-08-11 20:35:14

#include<bits/stdc++.h>
using namespace std;
#define maxn 100000
int m,n,i,j,S=300,P,nl,nr;
long long now;
char c[maxn+10];
long long cnt[maxn+10],a[maxn+10],b[maxn+10];
map<long long ,long long>mp;
struct ask
{
	int l,r,id;
	long long ans;
}s[maxn+10];
bool cmp(ask p,ask q)
{
	if((p.l-1)/S!=(q.l-1)/S)
	return p.l<q.l;
	return p.r<q.r;
}
bool cmp2(ask p,ask q)
{
	return p.id<q.id;
}
void add(int x)
{
//	printf("!%d ",x);
	now+=cnt[a[x]]++;
}
void del(int x)
{
//	printf("?%d ",x);
	now-=--cnt[a[x]];
}
int modui(int ql,int qr)
{
	while(qr>nr)add(++nr);//ºó¼Ó 
	while(ql<nl)add(--nl);//Ç°¼Ó 
	while(qr<nr)del(nr--);//ºó¼õ 
	while(ql>nl)del(nl++);//Ç°¼õ 
	return now;
}
int main()
{
	scanf("%d\n",&P);
	scanf("%s",c);
	n=strlen(c);
	for(i=0;i<n;i++)
	{
		a[i+1]=c[i]-'0';
		
	}
	
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&s[i].l,&s[i].r);
		s[i].id=i;
	}
	if(P==2||P==5)
	{
		long long sum=0;
		for(i=1;i<=n;i++)
		{
			if(a[i]%P==0)
			{
				a[i]=a[i-1]+i;
				b[i]=b[i-1]+1;
			}
			else
			{
				a[i]=a[i-1];
				b[i]=b[i-1];
			}
		}
		for(i=1;i<=m;i++)
		{
			printf("%lld\n",a[s[i].r]-a[s[i].l-1]-(b[s[i].r]-b[s[i].l-1])*(s[i].l-1));
		}
		return 0;
	}
	long long k=1;
	for(i=n;i>=1;i--)
	{
		a[i]=(a[i]*k+a[i+1])%P;
		b[i]=a[i];
		k=k*10%P;
	}
	sort(b+1,b+1+n);
	for(i=1;i<=n+1;i++)
	mp[b[i]]=i;
	for(i=1;i<=n+1;i++)
	a[i]=mp[a[i]];
	sort(s+1,s+1+m,cmp);
	nl=1,nr=0,now=0;
	for(i=1;i<=m;i++)
	{
		s[i].ans=modui(s[i].l,s[i].r+1);
	}
	sort(s+1,s+1+m,cmp2);
	for(i=1;i<=m;i++)
	{
		printf("%lld\n",s[i].ans);
	}
	return 0;
}

上一题