您的位置:首页 > 其它

HDU 4407 - Sum(容斥原理)

2015-01-31 15:09 309 查看
[align=left]Problem Description[/align]
XXX is puzzled with the question below:

1, 2, 3, ..., n (1<=n<=400000) are placed in a line. There are m (1<=m<=1000) operations of two kinds.

Operation 1: among the x-th number to the y-th number (inclusive), get the sum of the numbers which are co-prime with p( 1 <=p <= 400000).

Operation 2: change the x-th number to c( 1 <=c <= 400000).

For each operation, XXX will spend a lot of time to treat it. So he wants to ask you to help him.

 

[align=left]Input[/align]
There are several test cases.

The first line in the input is an integer indicating the number of test cases.

For each case, the first line begins with two integers --- the above mentioned n and m.

Each the following m lines contains an operation.

Operation 1 is in this format: "1 x y p".

Operation 2 is in this format: "2 x c".
 

[align=left]Output[/align]
For each operation 1, output a single integer in one line representing the result.

 

[align=left]Sample Input[/align]

1
3 3
2 2 3
1 1 3 4
1 2 3 6

 

[align=left]Sample Output[/align]

7
0

 

                                                            

题意:

1~n的数,两个操作:1.求出区间【x,y】中与c互质的数;2.将数列中的第x位的数改为c。

思路:

容斥原理。在操作一中将c的质因子存起来,在区间【x,y】中所有数的总和 - (整除两个质因子乘积的数和)+ (整除三个质因子乘积的数和)-(四个)。。。

注意在求总和的时候要用公式,不然会超时。

因为操作数只有1000以内,则可以使用数组将操作2的改变数的位置和数字存起来,记得之前改变过的位置如果再改变应该查找原来的那个数组位置,否则增加数组的个数,再操作一中遍历一遍。(一开始的思路:害怕每一次都遍历一遍会超时,所以试图使用lower_bound,但是此函数只对有序数列有用,使用时忽略了这一点!)

记得使用longlong,在这里wa了好久。

CODE:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long ll;
ll chgid[1005], chgp[1005];

ll solve(ll l, ll r, ll cn)
{
ll S = (r + 1)*r/2 - (l*(l - 1)/2);

vector<ll> p;
for(int i = 2; i*i <= cn; ++i) {
if(cn % i == 0) {
p.push_back(i);
while(cn % i == 0) cn /= i;
}
}
if(cn > 1) p.push_back(cn);

ll sum = 0, s = 0;
for(ll msk = 1; msk < (1<<p.size()); ++msk) {
ll mult = 1;
int bits = 0;
for(ll i = 0; i < p.size(); ++i) {
if(msk & (1<<i)) {
++bits;
mult *= p[i];
}
}

s = (mult + r/mult * mult)*(r/mult)/2 - (mult + (l-1)/mult * mult)*((l-1)/mult)/2;

if(bits % 2 == 1) sum += s;
else sum -= s;
}
return S - sum;
}

ll gcd(ll a, ll b)
{
if(b == 0) return a;
return gcd(b, a%b);
}

int main()
{
//freopen("in", "r", stdin);
ll T;
scanf("%I64d", &T);
while(T--) {
memset(chgid, 0, sizeof(chgid));
memset(chgp, 0, sizeof(chgp));

ll n, m, x, y, c;
ll g = 0;
scanf("%I64d %I64d", &n, &m);

while(m--) {
int op;
scanf("%d", &op);

if(op == 1) {
scanf("%I64d%I64d%I64d", &x, &y, &c);
ll Sum = solve(x, y, c);

for(int i = 0; i < g; ++i) {
if(chgid[i] >= x && chgid[i] <= y) {
if(gcd(chgid[i], c) == 1) Sum -= chgid[i];
if(gcd(chgp[i], c) == 1) Sum += chgp[i];
}
}
printf("%I64d\n",Sum);
}

else {
scanf("%I64d%I64d", &x, &c);
int i;
for(i = 0; i < g; ++i) {
if(chgid[i] == x) {
chgp[i] = c;
break;
}
}
if(i == g) {
chgid[g] = x;
chgp[g++] = c;
}

}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU