4542: [Hnoi2016]大数|莫队

HN一天考两个莫队是什么鬼..或者说莫队不是正确的姿势..?

考虑已经知道了l..r的答案新添入r+1如何更新当前答案

需要先预处理出后缀modp的值bi,假设子序列l..r模p的值为x

那么x?10r?l+b[r]=b[l] 然后就可以直接莫队统计了

模数为2或5的时候要特判一下

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<ctime>
#include<set>
#include<map>
#define N 110000
#define ll long long
using namespace std;
struct W{int l,r,p;}q[N];
char s[N];
long long sum[N],mod,ss[N],ans[N];
long long a[N],b[N],c[N],h[N],now;
int bl[N],cnt[N];
int n,m,Q,tot,block;
void solve_2_5()
{
    for(int i=1;i<=n;i++)
    {
        ss[i]=ss[i-1];
        sum[i]=sum[i-1];
        if((s[i]-‘0‘)%mod==0) sum[i]+=i,ss[i]++;
    }
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
    {
        int l,r;scanf("%d%d",&l,&r);
        printf("%lld\n",sum[r]-sum[l-1]-(ss[r]-ss[l-1])*(l-1));
    }
}
bool cmp(int x,int y)
{
    return b[x]<b[y];
}
bool cmp1(W a,W b)
{
    return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);
}
int main()
{
    scanf("%lld%s",&mod,s+1);
    n=strlen(s+1); block=sqrt(n);
    if(mod==2||mod==5)
    {
        solve_2_5();
        return 0;
    }
    a[0]=1;
    for(int i=1;i<=n;i++) a[i]=10*a[i-1]%mod;
    for(int i=n;i>=1;i--) b[i]=(a[n-i]*(s[i]-‘0‘)+b[i+1])%mod;
    for(int i=1;i<=n;i++) c[i]=i;
    sort(c+1,c+n+1,cmp);
    for(int i=1;i<=n;i++)
        if(b[c[i]]==b[c[i-1]]) h[c[i]]=tot;
        else h[c[i]]=++tot;
    for(int i=1;i<=n;i++) bl[i]=(i-1)/block;
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].p=i;
    sort(q+1,q+Q+1,cmp1);
    int L=1,R=0;
    for(int i=1;i<=Q;i++)
    {
        while(L>q[i].l) now+=cnt[h[L-1]]+(h[R+1]==h[L-1]),cnt[h[--L]]++;
        while(R<q[i].r) cnt[h[++R]]++,now+=cnt[h[R+1]];

        while(L<q[i].l) cnt[h[L]]--,now-=cnt[h[L]]+(h[R+1]==h[L]),L++;
        while(R>q[i].r) now-=cnt[h[R+1]],cnt[h[R--]]--;
        ans[q[i].p]=now;
    }
    for(int i=1;i<=Q;i++) printf("%lld\n",ans[i]);
    return 0;
}
时间: 2024-12-25 13:51:37

4542: [Hnoi2016]大数|莫队的相关文章

【BZOJ4542】[Hnoi2016]大数 莫队

[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

[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行,每行两个整数

[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)

正经题解在最下面 http://blog.csdn.net/qq_32739495/article/details/51286548 写的时候看了大神的题解[就是上面那个网址],看到下面这段话 观察题目,发现一串数s(l~r)整除p满足s(l~n-1)%p==s(r+1~n-1)%p 但p值为2或5不满足这个性质需要特判(不过数据中好像没有,于是笔者没写,有兴趣的可以自己去写写......) 然后问题转化为求一段区间中有几对相等的f值. 看到这里,我感觉豁然开朗,完全忽视了离散化的要求,我以为把

【BZOJ】4542: [Hnoi2016]大数

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4542 给定一个由数字构成的字符串${S_{1,2,3,...,n}}$,一个正素数$P$,每次询问给定一对$l$,$r$求: $${\sum_{l=1}^{n}\sum_{r=i}^{n}\left [ \sum _{i=l}^{r}S[i]*10^{r-i} \,\,\,\,MOD\,\,\,\,P=0 \right ]}$$ 即以位置$x$开头的后缀的数字$%P$之后的值为$val[

4540: [Hnoi2016]序列|莫队+ST表

考虑现在已经知道了[l,r]的答案新添入一个r+1如何更新答案 也就是右端点在r+1处左端点在l..r+1之间的所有的子序列的答案 可以找出l..r中最小的数的位置p,然后p以及p左侧作为左端点的答案就可以直接计算了 考虑左端点在p+1....r+1时对答案的贡献,可以与处理一个前缀和Si表示以i为右端点的所有子序列的答案之和 那么左端点在p+1....r+1时对答案的贡献就是Sr+1?Sp 其他端点移动的做法也同理 为什么我的莫队跑了17s,而网上的其他莫队只需要5s,人傻自带三倍常数QWQ

4542: [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行,每行两个整数

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

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4542 首先若p=2,5则这题就是道傻逼题,前缀和搞一下没了.如果p为其他质数,那么可以这么处理: 我们先预处理出数组num[i]表示原串第i~n位表示的数模p的余数,那么第l~r位表示的数模p的余数为(num[l]-num[r+1])/10^(n-r),因为10^(n-r)与p互质,所以若num[l]=num[r+1],则第l~r位表示的数是p的倍数.于是莫队一下就好了. 代码: #

【莫队】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.第二行

【BZOJ4540】【HNOI2016】序列(莫队)

[BZOJ4540][HNOI2016]序列(莫队) 题面 BZOJ 洛谷 Description 给定长度为n的序列:a1,a2,-,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,-,ar- 1,ar.若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列.现在有q个询问,每个询问给定两个数l和r,1≤l≤r ≤n,求a[l:r]的不同子序列的最小值之和.例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有 6个子序