挺有意思的,可以仔细体味一下的题;看白了就是莫队板子。

Description

  小 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的倍数。

Input

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

Output

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


题目分析

一个区间[l,r]产生贡献即$number_{i,j}\equiv 0\ ({\rm mod}\ p)$.

按照常见套路来说,应该把区间拆成关于端点的式子。用$pre[i]$表示前$i$位在十进制下的数值,那么即$number_{i,j}=pre[j]-10^{j-i+1}*pre[i-1]$。将式子移项发现左右两边形如$f(r)=f(l-1)$(据说这是一种经典的莫队套路)那么于此已经将区间问题转化为关于单点的可$O(1)$修改的子问题了。

之后的操作就相对套路:将$n+1$个$f(i)$(不要忘记统计$f(0)$)预先离散化处理;然后常规莫队操作。

注意莫队要先修改再更新!

 #include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
const int maxn = ; int blk[maxn];
struct QRs
{
int l,r,id;
bool operator < (QRs a) const
{
if (blk[l]==blk[a.l]) return r < a.r;
return blk[l] < blk[a.l];
}
}q[maxn];
char s[maxn];
int p,n,m,cnt,tot,size,inv10;
int lbd,rbd,lSd[maxn],rSd[maxn];
int ans[maxn],sum[maxn],pre[maxn],t[maxn]; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
int qmi(int a, int b)
{
int ret = ;
while (b)
{
if (b&) ret = 1ll*ret*a%p;
b >>= , a = 1ll*a*a%p;
}
return ret;
}
void lAdd(int lbd)
{
rSd[sum[lbd]]++, tot+=rSd[sum[lbd-]], lSd[sum[lbd-]]++;
}
void rAdd(int rbd)
{
lSd[sum[rbd-]]++, tot+=lSd[sum[rbd]], rSd[sum[rbd]]++;
}
void lErase(int lbd)
{
lSd[sum[lbd-]]--, tot-=rSd[sum[lbd-]], rSd[sum[lbd]]--;
}
void rErase(int rbd)
{
rSd[sum[rbd]]--, tot-=lSd[sum[rbd]], lSd[sum[rbd-]]--;
}
int main()
{
freopen("bignum.in","r",stdin);
freopen("bignum.out","w",stdout);
p = read(), scanf("%s",s+);
n = strlen(s+), size = sqrt(n+0.5)+;
if (p==||p==){
for (int i=; i<=n; i++)
{
ans[i] = ans[i-], sum[i] = sum[i-];
if ((s[i]-'')%p==) ans[i]++, sum[i] += i;
}
m = read();
for (int i=; i<=m; i++)
{
int l = read(), r = read();
printf("%d\n",sum[r]-sum[l-]-(ans[r]-ans[l-])*(l-));
}
return ;
}
for (int i=; i<=n; i++) blk[i] = i/size, pre[i] = (pre[i-]*10ll%p+s[i]-'')%p;
inv10 = qmi(, p-);
for (int i=, pr=; i<=n; i++)
t[i] = sum[i] = 1ll*pre[i]*pr%p, pr = 1ll*pr*inv10%p;
std::sort(t, t+n+), cnt = std::unique(t, t+n+)-t-;
for (int i=; i<=n; i++)
sum[i] = std::lower_bound(t, t+cnt+, sum[i])-t+;
m = read();
for (int i=; i<=m; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
std::sort(q+, q+m+);
lbd = , rbd = ;
for (int i=; i<=m; i++)
{
while (lbd < q[i].l) lErase(lbd++);
while (lbd > q[i].l) lAdd(--lbd);
while (rbd > q[i].r) rErase(rbd--);
while (rbd < q[i].r) rAdd(++rbd);
ans[q[i].id] = tot;
}
for (int i=; i<=m; i++) printf("%d\n",ans[i]);
return ;
}

END

【莫队】bzoj4542: [Hnoi2016]大数的更多相关文章

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

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

  2. bzoj4542 [Hnoi2016]大数 莫队+同余

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4542 题解 我们令 \(f_i\) 表示从 \(i\) 到 \(n\) 位组成的数 \(\bm ...

  3. BZOJ4542: [Hnoi2016]大数

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

  4. bzoj4542: [Hnoi2016]大数(莫队)

    这题...离散化...$N$和$n$搞错了...查了$2h$...QAQ 考虑$s[l...r]$,可以由两个后缀$suf[l]-suf[r+1]$得到$s[l...r]$代表的数乘$10^k$得到的 ...

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

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

  6. 【bzoj4542】[Hnoi2016]大数 莫队算法

    题目描述 给出一个数字串,多次询问一段区间有多少个子区间对应的数为P的倍数.其中P为质数. 输入 第一行一个整数:P.第二行一个串:S.第三行一个整数:M.接下来M行,每行两个整数 fr,to,表示对 ...

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

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

  8. 【bzoj5452】[Hnoi2016]大数(莫队)

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4542 首先若p=2,5则这题就是道傻逼题,前缀和搞一下没了.如果p为其他质数,那么可以 ...

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

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

随机推荐

  1. Java获取上周,本周,本月,本年,开始结束时间 。日期工具类

    由于获取日期经常会使用到,所有我自己写了一个工具类 1.基本上能用上的都写出来了,包括:1)获取当天的开始时间 2)获取当天的结束时间 3)获取昨天的开始时间 4)获取昨天的结束时间 5)获取明天的开 ...

  2. 重构之Divergent Change(发散式变化)&Shotgun Surgery (散弹式修改)

    5.Divergent Change发散式变化 描述:一个类被锚定了多个变化,当这些变化中的任意一个发生时,就必须对类进行修改. 解释:一个类最好只因一种变化而被修改 操作:你应该找出某特定原因而造成 ...

  3. mysql导入文件

    手里有一个web源码工程文件夹 mysql导入文件: 新建连接,名称随意,用修改设置的用户密码登录,我的连接名称是eee 右击information_schema,建立数据库,数据库名称源码文件名,字 ...

  4. js弹框怎么获得父页面的元素

    js获取父页面的元素可以用$(window.parent.document).find("#customer_id").val();这里的customer_id表示父页面某一个元素 ...

  5. Codeforces Round #378 (Div. 2) D. Kostya the Sculptor 分组 + 贪心

    http://codeforces.com/contest/733/problem/D 给定n个长方体,然后每个长方体都能选择任何一个面,去和其他长方体接在一起,也可以自己一个,要求使得新的长方体的最 ...

  6. Java虚拟机内存分配与回收策略

    内存分配与回收策略 Minor GC 和 Full GC Minor GC:发生在新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行, 执行的速度一般也会比较快. Full GC ...

  7. <context:property-placeholder>标签实现参数剥离

    <context:property-placeholder>标签提供了一种优雅的外在化参数配置的方式(可以是键值对的形式保存在.properties文件中),不过该标签在spring配置文 ...

  8. htmlparse

    <html>    <head>        <style>                textarea{                width:800p ...

  9. /usr/local/sbin/fping -s www.baidu.com www.google.com

    /usr/local/sbin/fping -s www.baidu.com www.google.com

  10. Leet-code144. Binary Tree Preorder Traversal

    这是一道将二叉树先序遍历,题目不难. 首先采用深搜递归 /** * Definition for a binary tree node. * public class TreeNode { * int ...