询问 x ~ y 与 p 互素的数字的和是多少。
因为询问+修改只有 1000 次,所以可以枚举修改的值。
1~n 有多少个数与p互素:将p拆成素因子,容斥定理搞一搞。
给出比赛时候的简陋代码。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<climits> 6 #include<cstdlib> 7 #include<cmath> 8 using namespace std; 9 #define N 1010 10 #define M 400010 11 typedef __int64 ll; 12 int prim[710], pr[710], top = 0, yi[20], tail; 13 int id[M]; 14 struct node { 15 int x, c; 16 }qu[N]; 17 void S(){ 18 memset(prim,0,sizeof(prim)); 19 prim[1]=prim[0]=1; 20 for(int i=2;i<=700;i++) 21 if(!prim[i]){ 22 pr[top++] = i; 23 for(int j=i*2;j<=700;j+=i) 24 prim[j]=1; 25 } 26 } 27 int pri(int x) { 28 int m = sqrt(1.0 * x), k = 0; 29 for (int i = 0; i < top && pr[i] <= m; ++i) { 30 if (x % pr[i] == 0) { 31 x /= pr[i]; 32 yi[k++] = pr[i]; 33 while (x % pr[i] == 0) x /= pr[i]; 34 } 35 } 36 if (x != 1) yi[k++] = x; 37 return k; 38 } 39 int Gcd(int a, int b) 40 { 41 if(b==0) return a; 42 return Gcd(b,a%b); 43 } 44 ll find(int x, int n, int p) { 45 ll ans = (ll)x*(x+1)/2; 46 for (int i = 1; i < 1<<n; ++i) { 47 int t = i, k = 0, num = 0; 48 ll temp = 1; 49 while (t) { 50 if (t&1) { 51 num++; 52 temp *= yi[k]; 53 } 54 t >>= 1; 55 ++k; 56 } 57 ll tb = ll(x)/temp; 58 if (num&1) ans -= temp*(1+tb)*tb/2; 59 else ans += temp*(1+tb)*tb/2; 60 } 61 for (int i = 0; i < tail; ++i) { 62 if (qu[i].x > x) continue; 63 int t2 = Gcd(qu[i].x, p); 64 int t1 = Gcd(qu[i].c, p); 65 if (t2 == 1) ans -= qu[i].x; 66 if (t1 == 1) ans += qu[i].c; 67 } 68 return ans; 69 } 70 int main() { 71 S(); 72 int T, n, m, f, x, y, c, p; 73 scanf("%d", &T); 74 while (T--) { 75 memset(id, -1, sizeof(id)); 76 tail = 0; 77 scanf("%d%d", &n, &m); 78 while (m--) { 79 scanf("%d", &f); 80 if (f == 2) { 81 scanf("%d%d", &x, &c); 82 if (id[x] == -1) { 83 id[x] = tail; 84 qu[tail].x = x; 85 qu[tail].c = c; 86 tail++; 87 } 88 else { 89 qu[id[x]].x = x; 90 qu[id[x]].c = c; 91 } 92 } 93 else { 94 scanf("%d%d%d", &x, &y, &p); 95 int n = pri(p); 96 printf("%I64d\n", find(y, n, p)-find(x-1, n, p)); 97 } 98 } 99 } 100 return 0; 101 }