http://acm.hdu.edu.cn/showproblem.php?
pid=4407
起初有n个数1~n。这里有m个操作。两种类型。操作1:求出[x,y]区间内与p互质的数的和。操作2:将第x位置的数变成y。对于每个询问,输出结果。
由于仅仅有1000次操作,并且起初是有序的。那么对于第i个询问,我们先忽略i之前的全部的第2种操作。即觉得n个数为1~n,依据容斥原理求出[x,y]区间内与p互质的数之和。然后遍历i之前的操作2,对所求的答案进行调整就可以。wa了无数次,改了好久。是由于我忽略的一点。对x位置的数有可能进行多次改动。我们仅仅需考虑最后一次改动就可以。所以可用用map保存一下操作2。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <bitset> #include <list> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> #define LL __int64 //#define LL long long #define eps 1e-9 #define PI acos(-1.0) using namespace std; const int maxn = 400010; int n,m; bool flag[maxn]; int prime[maxn]; int fac[100]; int facCnt; LL ans; map<int,int>M; int gcd(int a, int b) { if(b == 0) return a; return gcd(b,a%b); } void getPrime() { memset(flag,false,sizeof(flag)); prime[0] = 0; for(int i = 2; i < maxn; i++) { if(flag[i] == false) prime[++prime[0]] = i; for(int j = 1; j <= prime[0]&&prime[j]*i < maxn; j++) { flag[prime[j]*i] = true; if(i % prime[j] == 0) break; } } } void getFac(int num) { int tmp = num; facCnt = 0; for(int i = 1; i <= prime[0]&&prime[i]*prime[i] <= tmp; i++) { if(tmp % prime[i] == 0) { fac[facCnt++] = prime[i]; while(tmp % prime[i] == 0) tmp /= prime[i]; } if(tmp == 1) break; } if(tmp > 1) fac[facCnt++] = tmp; } LL getSum(int t) { return ((1 + 1LL * t) * 1LL * t) >> 1; } //求【1,r】内与该数互质的数之和。 LL cal(int r) { LL anw = getSum(r); LL tmp = 0; for(int i = 1; i < (1<<facCnt); i++) { LL mul = 1; int cnt = 0; for(int j = 0; j < facCnt; j++) { if(i&(1<<j)) { mul *= fac[j]; cnt++; } } if(cnt&1) tmp += mul * getSum((LL)r/mul); else tmp -= mul * getSum((LL)r/mul); } return anw - tmp; } int main() { getPrime(); int test; scanf("%d",&test); while(test--) { M.clear(); int op,x,y,z; scanf("%d %d",&n,&m); for(int i = 1; i <= m; i++) { scanf("%d",&op); if(op == 1) { scanf("%d %d %d",&x,&y,&z); getFac(z); ans = cal(y) - cal(x-1); //printf("ans : %I64d ",ans); map<int,int>::iterator it; for(it = M.begin(); it != M.end(); it++) { if(it->first >= x && it->first <= y) { if(gcd(z,it->first) == 1) ans -= it->first; if(gcd(z,it->second) == 1) ans += it->second; } } printf("%I64d ",ans); } else { scanf("%d %d",&x,&y); M[x] = y; } } } return 0; }