题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4407
此题与poj 2773解法相似, 都是先分解素数再用dfs实现容斥原理, 只不过这题求的是数字的和而不再是数字个数, 其实做法还是换汤不换药, 至于第二种操作, 注意到总的操作数只有1000所以发生改变的数很少, 可以暴力处理。
#include <iostream>
#include <stack>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <queue>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
const int N = 400005;
typedef long long LL;
LL c2(LL a) {
return a * (a + 1) >> 1;
}
bool vis[N];
int fac[N];
int prime[N];
int cnt, tar, x, y;
LL ans;
void sieve(int n) {
int m = sqrt(n + 0.5);
for (int i = 2; i <= m; i++) if (!vis[i])
for (int j = i * i; j <= n; j += i) vis[j] = 1;
}
int get_primes(int n) {
sieve(n);
int c = 0;
for (int i = 2; i <= n; i++)
if (!vis[i])
prime[c++] = i;
return c;
}
map<int, int> Map;
void dfs(int id, int now, LL& res, int v, bool flag) {
if (id == cnt) return;
dfs(id + 1, now, res, v, flag);
int key = now * fac[id];
if (flag)
res += c2(v / key) * key;
else
res -= c2(v / key) * key;
dfs(id + 1, key, res, v, !flag);
}
LL gao(int n) {
LL res = 0;
dfs(0, 1, res, n, 1);
return c2(n) - res;
}
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
void solve(pair<int, int> p) {
int a = p.first, b = p.second;
bool f1 = gcd(a, tar) == 1 && (a >= x && a <= y);
bool f2 = gcd(b, tar) == 1 && (a >= x && a <= y);
if (f1 && !f2) ans -= a;
else if (f2 && !f1) ans += b;
else if (f1 && f2) ans += (b - a);
}
int main() {
int op, v, test, n, m;
int c = get_primes(N - 5);
scanf("%d", &test);
while (test--) {
Map.clear();
scanf("%d%d", &n, &m);
while (m--) {
scanf("%d", &op);
if (op == 1) {
scanf("%d%d%d", &x, &y, &v);
tar = v;
cnt = 0;
for (int i = 0; prime[i] <= v; i++) {
while (v % prime[i] == 0) {
fac[cnt++] = prime[i];
v /= prime[i];
}
}
cnt = unique(fac, fac + cnt) - fac;
ans = gao(y) - gao(x - 1);
for_each(Map.begin(), Map.end(), solve);
printf("%I64d\n", ans);
}
else {
scanf("%d%d", &x, &v);
Map[x] = v;
}
}
}
return 0;
}