[BZOJ4026]dC Loves Number Theory
[BZOJ4026]dC Loves Number Theory
试题描述
dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源。
给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代表1~n 中与n互质的数的个数) 。由于答案可能很大,所以请对答案 mod (10^6 + 777)。 (本题强制在线,所有询问操作的l,r都需要 xor上一次询问的答案 lastans,初始时,lastans = 0)
输入
第一行,两个正整数,N,Q,表示序列的长度和询问的个数。
第二行有N 个正整数,第i个表示Ai.
下面Q行,每行两个正整数,l r,表示询问[l ^ lastans,r ^ lastans]内所有元素乘积的φ
输出
Q行,对于每个询问输出一个整数。
输入示例
5 10 3 7 10 10 5 3 4 42 44 241 242 14 9 1201 1201 0 6 245 245 7 7 6 1 1203 1203
输出示例
40 240 12 1200 2 240 4 4 1200 4
数据规模及约定
1 <= N <= 50000
1 <= Q <= 100000
1 <= Ai <= 10^6
题解
把原序列中每个数 Ai 拆成不超过 logAi 个质因数,然后思路基本和上一题一样,只不过维护的东西换了(提示:想想怎么求 φ)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 800010
#define maxnode 12800010
#define maxp 1000010
#define maxlog 20
#define MOD 1000777
#define LL long long
int A[maxn], nn, pos[maxn], lstp[maxp], Mulsum[maxn], inv[MOD];
void gcd(int a, int b, int& x, int& y) {
if(!b){ x = 1; y = 0; return ; }
gcd(b, a % b, y, x); y -= a / b * x;
return ;
}
int Inv(int a) {
int x, y;
gcd(a, MOD, x, y);
return (x % MOD + MOD) % MOD;
}
int prime[maxp], cnt, val[maxp], nxt[maxp], tval[maxlog];
bool vis[maxp];
void prime_table() {
for(int i = 2; i <= maxp - 10; i++) {
if(!vis[i]) prime[++cnt] = i, val[i] = prime[cnt], nxt[i] = i;
for(int j = 1; j <= cnt && i * prime[j] <= maxp - 10; j++) {
vis[i*prime[j]] = 1;
val[i*prime[j]] = prime[j]; nxt[i*prime[j]] = i;
if(i % prime[j] == 0) break;
}
}
return ;
}
int ToT, rt[maxn], Mul[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p, int v) {
if(v > 1) Mul[y = ++ToT] = ((LL)Mul[x] * (v - 1) % MOD) * inv[v] % MOD;
else Mul[y = ++ToT] = Mul[x];
// printf("%d %d %d: %d(%d %d %d)\n", y, l, r, Mul[y], x, v, inv[v]);
if(l == r) return ;
int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
else update(rc[y], rc[x], mid + 1, r, p, v);
return ;
}
LL query(int o, int l, int r, int qr) {
if(!o) return 1;
if(r <= qr) return Mul[o];
int mid = l + r >> 1;
LL ans = query(lc[o], l, mid, qr);
if(qr > mid) (ans *= query(rc[o], mid + 1, r, qr)) %= MOD;
return ans;
}
int ANS[maxn], len;
char Out[maxn];
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
for(int i = 0; i < MOD; i++) inv[i] = Inv(i);
prime_table();
int n = read(), q = read();
Mulsum[0] = 1;
for(int i = 1; i <= n; i++) {
int tmp = read();
Mulsum[i] = (LL)Mulsum[i-1] * tmp % MOD;
pos[i] = nn + 1;
if(tmp == 1) A[++nn] = 1;
else {
int j = tmp, tc = 0;
for(; nxt[j] != j; j = nxt[j]) tval[++tc] = val[j];
tval[++tc] = val[j];
tc = unique(tval + 1, tval + tc + 1) - tval - 1;
for(j = 1; j <= tc; j++) A[++nn] = tval[j];
}
}
pos[n+1] = nn + 1;
n = nn; Mul[0] = 1;
for(int i = 1; i <= n; i++) {
update(rt[i], rt[i-1], 0, n, lstp[A[i]], A[i]);
lstp[A[i]] = i;
}
/*printf("n: %d\n", n);
for(int i = 1; i <= n; i++) printf("%d%c", A[i], i < n ? ' ' : '\n');
for(int i = 1; i <= n; i++) printf("%d ", pos[i]); putchar('\n');*/
int lst = 0;
for(int i = 1; i <= q; i++) {
int ql = read() ^ lst, qr = read() ^ lst;
int l = pos[ql], r = pos[qr+1] - 1;
int Multi = (LL)Mulsum[qr] * inv[Mulsum[ql-1]] % MOD;
// printf("Multi: %d %d %d %d %d\n", Multi, rt[r], rt[l-1], query(rt[r], 0, n, l - 1), query(rt[l-1], 0, n, l - 1));
lst = (query(rt[r], 0, n, l - 1) * inv[query(rt[l-1],0,n,l-1)] % MOD) * Multi % MOD;
ANS[i] = lst;
// lst = 0;
}
int num[10], cntn;
for(int i = 1; i <= q; i++) {
int tmp = ANS[i];
// printf("%d\n", ANS[i]);
if(!tmp) Out[len++] = '0';
cntn = 0;
while(tmp) num[++cntn] = tmp % 10, tmp /= 10;
for(int j = cntn; j; j--) Out[len++] = num[j] + '0';
if(i < q) Out[len++] = '\n'; else Out[len++] = '\0';
}
puts(Out);
return 0;
}
不知为何把求逆元的部分都改成 long long 交到大视野上就 T 飞,害得我差点调了一年。。。
2017-4-21
上面代码又臭又长,我补一个好看点的。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 50010
#define maxnum 1000010
#define maxnode 20000010
#define MOD 1000777
#define LL long long
int n, Sum[maxn], lst[maxnum], rt[maxn];
void gcd(LL a, LL b, LL& x, LL& y) {
if(!b){ x = 1; y = 0; return ; }
gcd(b, a % b, y, x); y -= a / b * x;
return ;
}
int Inv(int a) {
LL x, y;
gcd(a, MOD, x, y);
return (x % MOD + MOD) % MOD;
}
int ToT, Fac[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p, int v) {
Fac[y = ++ToT] = (LL)Fac[x] * v % MOD;
if(l == r) return ;
int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
else update(rc[y], rc[x], mid + 1, r, p, v);
return ;
}
int query(int o, int l, int r, int qr) {
if(r <= qr) return Fac[o];
int mid = l + r >> 1, ans = query(lc[o], l, mid, qr);
if(qr > mid) ans = (LL)ans * query(rc[o], mid + 1, r, qr) % MOD;
return ans;
}
int main() {
n = read(); int q = read();
Fac[0] = Sum[0] = 1;
for(int i = 1; i <= n; i++) {
int A = read();
Sum[i] = (LL)Sum[i-1] * A % MOD;
int m = sqrt(A + .5);
rt[i] = rt[i-1];
for(int x = 2; x <= m; x++) if(A % x == 0) {
update(rt[i], rt[i], 0, n, lst[x], (LL)(x - 1) * Inv(x) % MOD); lst[x] = i;
while(A % x == 0) A /= x;
}
if(A > 1) update(rt[i], rt[i], 0, n, lst[A], (LL)(A - 1) * Inv(A) % MOD), lst[A] = i;
}
int lstans = 0;
while(q--) {
int l = read() ^ lstans, r = read() ^ lstans;
printf("%d\n", lstans = (LL)Sum[r] * Inv(Sum[l-1]) % MOD * query(rt[r], 0, n, l - 1) % MOD * Inv(query(rt[l-1], 0, n, l - 1)) % MOD);
}
return 0;
}

浙公网安备 33010602011771号