您的位置:首页 > 其它

HDU 4407 (容斥)

2016-07-05 19:53 197 查看

题目链接:点击这里

题意: 给出1,2,3…n这个序列, 然后两种操作: 求某一个闭区间和p互质的数的和; 改变某一个数.

因为操作数比较少, 所以改变可以都存下来, 计算原区间的结果, 然后用存下来的改变更新下就好了. 区间互质的和可以容斥可以反演很ez.

#include <bits/stdc++.h>
using namespace std;
#define maxn 400005

int n, m;
struct node {
int id, num;
bool operator < (const node &a) const {
return id < a.id;
}
bool operator == (const node &a) const {
return id == a.id;
}
};
set <node> gg;
set <node>::iterator it;
vector <int> fac[maxn];//每一个数的素因子

bool is_prime[maxn];
int prime[maxn], cnt;
void init () {
cnt = 0;
for (int i = 0; i < maxn; i++) fac[i].clear ();
memset (is_prime, 1, sizeof is_prime);
is_prime[0] = is_prime[1] = 0;
for (int i = 2; i < maxn; i++) if (is_prime[i]) {
prime[cnt++] = i;
fac[i].push_back (i);
for (int j = i+i; j < maxn; j += i) {
fac[j].push_back (i);
is_prime[j] = 0;
}
}
}

int cal (int num, int &mul, int x) {
mul = 1;
int ans = 0, Max = fac[x].size ();
for (int i = 1; i <= Max; i++, num >>= 1) {
if (num&1) {
ans++;
mul *= fac[x][i-1];
}
}
return ans;
}

long long solve (int pos, int num) {//[1,pos]中和num互质的数
if (pos < 1) return 0;
long long ans = 0;
int Max = (1<<fac[num].size ());
for (int i = 1; i < Max; i++) {
int mul;
int num_of_1 = cal (i, mul, num);
long long cnt = pos/mul, sum = (mul+1LL*mul*cnt)*cnt/2;
if (num_of_1&1) {
ans += sum;
}
else
ans -= sum;
}
ans = (1LL*pos+1)*pos/2-ans;
return ans;
}

int main () {
int t;
scanf ("%d", &t);
init ();
while (t--) {
scanf ("%d%d", &n, &m);
gg.clear ();
for (int i = 1; i <= m; i++) {
int op, x, y, num;
scanf ("%d", &op);
if (op == 1) {
scanf ("%d%d%d", &x, &y, &num);
long long ans = solve (y, num)-solve (x-1, num);
for (it = gg.begin (); it != gg.end (); it++) {
if (it->id >= x && it->id <= y) {
int pos = it->id, cur = it->num;
if (__gcd (num, pos) == 1) ans -= pos;
if (__gcd (cur, num) == 1) ans += cur;
}
}
printf ("%lld\n", ans);
}
else {
scanf ("%d%d", &x, &y);
gg.erase ((node) {x, 0});
gg.insert ((node) {x, y});
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: