首页 > 代码库 > 【莫比乌斯反演+树状数组+分块求和】GCD Array

【莫比乌斯反演+树状数组+分块求和】GCD Array

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/I

【题意】

给定长度为l的一个数组,初始值为0;规定了两种操作:

技术分享

【思路】

找到了一个讲解很清楚的博客http://www.cnblogs.com/flipped/p/HDU4947.html

技术分享

技术分享

技术分享

【Accepted】

技术分享
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <stack>
  7 #include <queue>
  8 #include <string>
  9 #include <vector>
 10 #include <set>
 11 #include <map>
 12 #include <cassert>
 13 using namespace std;
 14 
 15 #define CLR(a,b) memset(a,b,sizeof(a))
 16 typedef long long LL;
 17 const int N = 200000+20;
 18 bool check[N];
 19 int mu[N],prime[N];
 20 
 21 vector<int> fac[N];
 22 LL f[N];
 23 int l,q;
 24 
 25 void Mobius()
 26 {
 27     CLR(check, 0);
 28     mu[1] = 1;
 29     int tot = 0;
 30     for(int i = 2; i < N ; i++){
 31         if(!check[i]){
 32             prime[tot ++] = i;
 33             mu[i] = -1;
 34         }
 35         for(int j = 0 ;j < tot; j ++){
 36             if(i * prime[j] >= N)break;
 37             check[i * prime[j]] = true;
 38             if(i % prime[j] == 0){
 39                 mu[i * prime[j]] = 0;
 40                 break;
 41             }else{
 42                 mu[i * prime[j]] = -mu[i];
 43             }
 44         }
 45     }
 46     for(int i = 1 ;i < N ; i++){
 47         for(int j = i ; j < N ; j += i){
 48             fac[j].push_back(i);
 49         }
 50     }
 51 }
 52 
 53 inline LL sum(int p){
 54     LL s = 0;
 55     while(p > 0){
 56         s += f[p];
 57         p -= p & (-p);
 58     }
 59     return s;
 60 }
 61 
 62 inline void add(int p,int v){
 63     while(p <= l){
 64         f[p] += v;
 65         p += (p) & (-p);
 66     }
 67 }
 68 
 69 void update(int n,int d,int v){
 70     if(n % d != 0)return;
 71     
 72     n = n/d;
 73     for(int i = 0 ;i < fac[n].size() ; i++){
 74         int q = fac[n][i];
 75         add(q * d, v * mu[q]);
 76     }
 77 }
 78 
 79 LL query(int p)
 80 {
 81     LL ans = 0;
 82     for(int i = 1,last = i ; i <= p ; i = last + 1){
 83         last = p/(p/i);
 84         ans += (LL)(p/i) * (sum(last) - sum(i-1)) ;
 85     }
 86     return ans;
 87 }
 88 
 89 int main()
 90 {
 91     Mobius();
 92     int cas = 0;
 93     while(~scanf("%d%d",&l,&q)){
 94         if(l == 0 && q == 0)break;
 95         CLR(f, 0);
 96         cas ++;
 97         printf("Case #%d:\n",cas);
 98         while(q--){
 99             int t;
100             scanf("%d",&t);
101             if(t == 1){
102                 int n,d,v;
103                 scanf("%d%d%d",&n,&d,&v);
104                 update(n, d, v);
105             }else{
106                 int x;
107                 scanf("%d",&x);
108                 printf("%I64d\n",query(x));
109             }
110         }
111     }
112     return 0;
113 }
114 
115 /*
116 
117  6 4
118  1 4 1 2
119  2 5
120  1 3 3 3
121  2 3
122  0 0
123 
124 */
View Code

 

 

 

 

【莫比乌斯反演+树状数组+分块求和】GCD Array