您的位置:首页 > 其它

HDU 4407 Sum(容斥)

2017-10-31 22:29 351 查看
题意:一个长度为n的序列(初始为1, 2, 3, ...n),现在q次操作,操作1:给你L,R, p, 求区间[L, R]中与p互质的数的和;

操作2:修改第x个数为c。(n <= 4e5, q <= 1e3)

思路:因为序列是1-n,所以区间求和可以利用容斥,因为q才1000,所以修改可以存起来,查询时暴力更新。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+5;
int n, q, x, y, num, yz[maxn];
ll ans;
map<int, int> m;

void dfs(int cur, ll fac, int id)
{
ll tmp1, tmp2;
if(id%2)
{
ll n = y, d = fac;
ans -= (ll)(d+(n/d)*d)*(n/d)/2;
n = x-1;
ans += (ll)(d+(n/d)*d)*(n/d)/2;
}
else
{
ll n = y, d = fac;
ans += (ll)(d+(n/d)*d)*(n/d)/2;
n = x-1;
ans -= (ll)(d+(n/d)*d)*(n/d)/2;
}
for(int i = cur+1; i < num; i++)
dfs(i, fac*yz[i], id+1);
}

int main(void)
{
int _;
cin >> _;
while(_--)
{
m.clear();
scanf("%d%d", &n, &q);
while(q--)
{
int cmd, p, c;
scanf("%d%d", &cmd, &x);
if(cmd == 1)
{
scanf("%d%d", &y, &p);
num = 0;
int tt = p;
for(int i = 2; i*i <= tt; i++)
{
if(tt % i == 0)
{
yz[num++] = i;
while(tt % i == 0) tt /= i;
}
}
if(tt != 1) yz[num++] = tt;
ans = (ll)(x+y)*(y-x+1)/2;
for(int i = 0; i < num; i++)
dfs(i, yz[i], 1);
map<int, int>::iterator it;
for(it = m.begin(); it != m.end(); it++)
{
int fir = it->first;
int sec = it->second;
if(fir >= x && fir <= y)
{
if(__gcd(fir, p) == 1)
{
if(__gcd(sec, p) == 1) ans = ans-fir+sec;
else ans = ans-fir;
}
else
{
if(__gcd(sec, p) == 1) ans = ans+sec;
}
}
}
printf("%lld\n", ans);
}
else
{
scanf("%d", &c);
m[x] = c;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU 容斥