【莫队】bzoj4542: [Hnoi2016]大数
挺有意思的,可以仔细体味一下的题;看白了就是莫队板子。
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]大数的更多相关文章
- [BZOJ4542] [Hnoi2016] 大数 (莫队)
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
- bzoj4542 [Hnoi2016]大数 莫队+同余
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4542 题解 我们令 \(f_i\) 表示从 \(i\) 到 \(n\) 位组成的数 \(\bm ...
- BZOJ4542: [Hnoi2016]大数
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
- bzoj4542: [Hnoi2016]大数(莫队)
这题...离散化...$N$和$n$搞错了...查了$2h$...QAQ 考虑$s[l...r]$,可以由两个后缀$suf[l]-suf[r+1]$得到$s[l...r]$代表的数乘$10^k$得到的 ...
- 【BZOJ4542】[Hnoi2016]大数 莫队
[BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个 ...
- 【bzoj4542】[Hnoi2016]大数 莫队算法
题目描述 给出一个数字串,多次询问一段区间有多少个子区间对应的数为P的倍数.其中P为质数. 输入 第一行一个整数:P.第二行一个串:S.第三行一个整数:M.接下来M行,每行两个整数 fr,to,表示对 ...
- BZOJ.4542.[HNOI2016]大数(莫队)
题目链接 大数除法是很麻烦的,考虑能不能将其条件化简 一段区间[l,r]|p,即num[l,r]|p,类似前缀,记后缀suf[i]表示[i,n]的这段区间代表的数字 于是有 suf[l]-suf[r+ ...
- 【bzoj5452】[Hnoi2016]大数(莫队)
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4542 首先若p=2,5则这题就是道傻逼题,前缀和搞一下没了.如果p为其他质数,那么可以 ...
- 洛谷P3245 [HNOI2016]大数(莫队)
题意 题目链接 Sol 莫队板子题.. 维护出每个位置开始的字符串\(mod P\)的结果,记为\(S_i\) 两个位置\(l, r\)满足条件当且仅当\(S_l - S_r = 0\),也就是\(S ...
随机推荐
- Ubuntu设置打不开排错
记录一次系统设置打不开排错过程 系统信息: ××××××:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu ...
- 这几道Python面试题,稳准狠,Python面试题No15
必须放一个表情包,太魔性了! 第1题: 修改以下Python代码,使得下面的代码调用类A的show方法? 原始代码 class A(object): def run(self): print(&quo ...
- phpstorm使用
生成注释快捷键/**+enter 注释快捷键ctrl+/
- BZOJ 1433 && Luogu P2055 [ZJOI2009]假期的宿舍 匈牙利算法
刚学了匈牙利正好练练手(我不会说一开始我写错了)(怕不是寒假就讲了可是我不会) 把人看做左部点,床看作右部点 建图:(!!在校相当于有床,不在校相当于没有床 但是要来学校) 1.在校的 不走的人 自己 ...
- Jmeter4.0----测试数据说明之查看结果树(10)
1.说明 在用jmeter辅助测试的过程中,我们经常需要根据接口返回的相关信息对我们测试的系统做相应的分析,所以呢,常常会用到jmeter中不同类型的监听器获取接口信息. 2.步骤 第一步: 线程组 ...
- AspNet Zero Core
解决AspNet Zero Core 5.0.1无法运行的问题 最近在研究AspNet Zero Core 5.0.1时发现VS点击调试后就自动退出了,从ABP QQ群里得知作者加入了licens ...
- bzoj 2301: [HAOI2011]Problem b mobius反演 RE
http://www.lydsy.com/JudgeOnline/problem.php?id=2301 设f(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) = i的个数. 设F( ...
- C - AtCoDeerくんと選挙速報 / AtCoDeer and Election Report
ceil有毒啊..用ceil一直错. 思路就是模拟吧,设当前的答案是ansx和ansy. 如果比例是小于ansx的,那么就要乘以一个倍数k1,使得a * k1 >= ansx的. 所以就用cei ...
- java获取服务器一些信息的方法
request.getServletContext().getRealPath("/") 获取项目所在服务器的全路径,如:D:\Program Files\apache-tomca ...
- Mybatis基础配置及增删查改操作
一.简介 平时我们都用JDBC访问数据库,除了需要自己写SQL之外,还必须操作Connection, Statement, ResultSet 这些其实只是手段的辅助类. 不仅如此,访问不同的表,还会 ...