BZOJ 4542 [Hnoi2016]大数
2017-03-25 00:18
381 查看
莫队
记sum是前缀和,一对合法的i,j必定满足(sumi−sumj−1∗10i−j+1) mod p=0
移项一下,把10的幂分给两边,sumi10i≡sumj−110j−1 mod p
这样两边就分别和i,j相关,题目就转化为区间内有多少对这样的相同的点对。
由于区间内每一个数字都可以贡献,即每一个数都要查,线段树之类的区间数据结构不太好用了。考虑减少查询次数,莫队即可。一个坑点是当P=2或5时,上面移项之后,10没有逆元不能进行除法。需要特判一下尾数。
记sum是前缀和,一对合法的i,j必定满足(sumi−sumj−1∗10i−j+1) mod p=0
移项一下,把10的幂分给两边,sumi10i≡sumj−110j−1 mod p
这样两边就分别和i,j相关,题目就转化为区间内有多少对这样的相同的点对。
由于区间内每一个数字都可以贡献,即每一个数都要查,线段树之类的区间数据结构不太好用了。考虑减少查询次数,莫队即可。一个坑点是当P=2或5时,上面移项之后,10没有逆元不能进行除法。需要特判一下尾数。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<cstring> #define N 100005 using namespace std; namespace runzhe2000 { typedef long long ll; char str ; ll sum ; int p, n, m, a , S, block , arr[N<<1], arrcnt, cnt1[N<<1], cnt0[N<<1]; ll out ; struct query { int l, r, id; bool operator < (const query &that) const {return block[l] == block[that.l] ? r < that.r : block[l] < block[that.l];} }q ; int fpow(int a, int b) { int r = 1; for(; b; b>>=1) {if(b&1)r=(ll)r*a%p; a=(ll)a*a%p; } return r; } int inv(int a){return fpow(a,p-2);} void solve1() { sort(q+1, q+1+m); for(int i = 1; i <= n; i++) sum[i] = (sum[i-1] * 10ll + a[i]) % p, arr[++arrcnt] = (ll)sum[i] * inv(fpow(10, i)) % p; arr[++arrcnt] = 0; sort(arr+1, arr+1+arrcnt); arrcnt = unique(arr+1, arr+1+arrcnt) - arr - 1; for(int i = 0; i <= n; i++) sum[i] = lower_bound(arr+1, arr+1+arrcnt, (ll)sum[i] * inv(fpow(10, i)) % p) - arr; q[0].l = 0; int r = 0, ans = 0; for(int i = 1; i <= m; i++) { if(block[q[i].l] != block[q[i-1].l]) { memset(cnt0, 0, sizeof(cnt0)); memset(cnt1, 0, sizeof(cnt1)); r = min(S * block[q[i].l], n); ans = 0; } if(block[q[i].l] == block[q[i].r]) { for(int j = q[i].l; j <= q[i].r; j++) { cnt1[sum[j-1]]++; ans += cnt1[sum[j]]; } out[q[i].id] = ans; for(int j = q[i].r; j >= q[i].l; j--) { ans -= cnt1[sum[j]]; cnt1[sum[j-1]]--; } } else { for(; r < q[i].r;) { r++; cnt1[sum[r-1]]++; ans += cnt1[sum[r]]; cnt0[sum[r]]++; } int l = min(S * block[q[i].l], n) + 1; for(; q[i].l < l; ) { l--; cnt0[sum[l]]++; ans += cnt0[sum[l-1]]; cnt1[sum[l-1]]++; } out[q[i].id] = ans; for(int j = l, jj = min(block[q[i].l] * S, n); j <= jj; j++) { cnt1[sum[j-1]]--; ans -= cnt0[sum[j-1]]; cnt0[sum[j]]--; } } } } void solve2() { for(int i = 1; i <= n; i++) sum[i] = sum[i-1] + (a[i] % p == 0 ? i : 0), cnt0[i] = cnt0[i-1] + (a[i] % p == 0 ? 1 : 0); for(int i = 1; i <= m; i++) { out[i] = sum[q[i].r] - sum[q[i].l - 1]; out[i] -= (q[i].l - 1) * (cnt0[q[i].r] - cnt0[q[i].l - 1]); } } void main() { scanf("%d%s",&p,str+1); n = strlen(str + 1); S = sqrt(n); scanf("%d",&m); for(int i = 1; i <= n; i++) a[i] = str[i] - '0', block[i] = (i-1) % S == 0 ? block[i-1]+1 : block[i-1]; for(int i = 1; i <= m; i++) scanf("%d%d",&q[i].l,&q[i].r), q[i].id = i; if(p != 2 && p != 5) solve1(); else solve2(); for(int i = 1; i <= m; i++) printf("%lld\n",out[i]); } } int main() { runzhe2000::main(); }
相关文章推荐
- BZOJ 4542: [Hnoi2016]大数
- bzoj4542: [Hnoi2016]大数
- bzoj4542【HNOI2016】大数
- [BZOJ4542][Hnoi2016]大数(莫队+数学相关)
- bzoj 4542: [Hnoi2016]大数
- BZOJ.4542.[HNOI2016]大数(莫队)
- [BZOJ4542][HNOI2016]大数(莫队)
- [bzoj4542][HNOI2016]大数
- BZOJ4542: [Hnoi2016]大数
- bzoj 4542: [Hnoi2016]大数
- [莫队] BZOJ 4542 [Hnoi2016]大数
- BZOJ4542: [Hnoi2016]大数
- Bzoj4542--Hnoi2016大数
- BZOJ 4542: [Hnoi2016]大数
- BZOJ4542: [Hnoi2016]大数
- bzoj4542 [Hnoi2016]大数
- bzoj4542: [Hnoi2016]大数
- [BZOJ4542][Hnoi2016]大数(莫队+特判)
- bzoj4542 [Hnoi2016]大数
- [bzoj 4542] [Hnoi2016]大数:莫队算法