您的位置:首页 > 其它

【bzoj4542】[Hnoi2016]大数 莫队

2016-04-20 19:54 363 查看

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个询问的答案。

Sample Input

11

121121

3

1 6

1 5

1 4


Sample Output

5

3

2


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

HINT

2016.4.19新加数据一组

Source

感觉可以离线?

用a[i]表示前i个数连起来的数,则题目让求:

∑l∑r[s[r]−s[l−1]∗10r−l+1=0 (mod p)]

=∑l∑r[s[r]=s[l−1]∗10r−l+1 (mod p)]

=∑l∑r[s[r]∗(10r)−1=s[l−1]∗(10l−1)−1 (mod p)]

把s[i]∗(10i)−1离散化一下就是经典的莫队了。

然后关于p=2或5需要特判,因为这时候10i没有逆元,前缀和一下就行了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;

typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;

int B,len,t[SZ],cnt = 0,n;

map<LL,int> mp;

LL s[SZ],p;

char str[SZ];

struct haha{
int l,r,id;
LL ans;
}ask[SZ];

bool cmp1(haha a,haha b)
{
if(a.l / B == b.l / B) return a.r < b.r;
return a.l < b.l;
}

bool cmp2(haha a,haha b)
{
return a.id < b.id;
}

int id[SZ];

LL get(LL x)
{
return x * (x - 1);
}

namespace work25{
int t[SZ],sum[SZ];
void solve()
{
for(int i = 1;i <= n;i ++)
{
if((str[i] - '0') % p == 0)
t[i] = t[i - 1] + 1,sum[i] = sum[i - 1] + i;
else
t[i] = t[i - 1],sum[i] = sum[i - 1];
}
int m;
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",(sum[r] - sum[l - 1]) - ((LL)t[r] - t[l - 1]) * (l - 1));
}
}
}

int main()
{
scanf("%lld",&p);
scanf("%s",str + 1);
n = strlen(str + 1);

if(p == 2 || p == 5)
{
work25 :: solve();
return 0;
}

B = sqrt(n);
for(int i = n;i >= 1;i --)
{
static LL x = 1;
x = x * 10 % p;
s[i] = (s[i + 1] + x * (str[i] - '0') % p) % p;
if(!mp[s[i]]) mp[s[i]] = ++ cnt;
}

for(int i = 1;i <= n + 1;i ++)
id[i] = mp[s[i]];

int m;
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
scanf("%d%d",&ask[i].l,&ask[i].r); ask[i].r ++;
ask[i].id = i;
}

sort(ask + 1,ask + 1 + m,cmp1);
LL ans = 0;
for(int i = 1,l = 1,r = 0;i <= m;i ++)
{
for(;r > ask[i].r;r --) { ans -= get(t[id[r]]); t[id[r]] --; ans += get(t[id[r]]); }
for(;r < ask[i].r;r ++) { ans -= get(t[id[r + 1]]); t[id[r + 1]] ++; ans += get(t[id[r + 1]]); }
for(;l > ask[i].l;l --) { ans -= get(t[id[l - 1]]); t[id[l - 1]] ++; ans += get(t[id[l - 1]]); }
for(;l < ask[i].l;l ++) { ans -= get(t[id[l]]); t[id[l]] --; ans += get(t[id[l]]); }
ask[i].ans = ans >> 1;
}

sort(ask + 1,ask + 1 + m,cmp2);
for(int i = 1;i <= m;i ++)
printf("%lld\n",ask[i].ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: