2017 Multi-University Training Contest - Team 6 7.GCDispower(数论+离线处理+容斥原理)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6102

题解:

分析:有点难想。。首先逐个加入右端点,每加入一个,枚举倍数,和题解做法一样,然后更新每个Ai位置的值,当某个区间右端点恰好的刚刚枚举完的右端点时,这时候更新答案,对应询问的答案就是这个时候的区间和,用树状数组处理一下,可以先把询问按右端点从小到大排序,方便查找右端点恰好达到的区间。

然后求互质个数的容斥,具体来说,首先预处理出1~1e5的数的因子和莫比乌斯函数,然后把右端点的倍数,从右往左扫,每加入一个新的,把它分解,然后查找它后面是某个因子倍数的数个数,容斥一下,再更新一下倍数的个数,更新一下该点的答案,继续往左扫,做完以后把个数清空,再做下一次的。可以做一个剪枝,直接把因子对应莫比乌斯函数为0的不放入预处理的数组中。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<vector>
  5 #include<algorithm>
  6 using namespace std;
  7 typedef long long ll;
  8 const int maxn=1e5+5;
  9 int pri[maxn],len=0,mu[maxn];
 10 bool Is_pri[maxn];
 11 vector<int> factor[maxn];
 12 int n,m,a[maxn],l[maxn],r[maxn],order[maxn],loca[maxn];
 13 ll  ans[maxn];
 14 int temp[maxn],num[maxn],cnt=0;
 15 bool Cmp(int a,int b){return r[a]<r[b];}
 16 class TreeArray{
 17     ll c[maxn];
 18     int n;
 19 public:
 20     void init(int n){
 21         this->n=n;
 22         memset(c,0,sizeof(c));
 23     }
 24     void add(int k,ll num){
 25         while(k<=n){
 26             c[k]+=num;
 27             k+=k&-k;
 28         }
 29     }
 30     ll query(int k){
 31         ll sum=0;
 32         while(k){
 33             sum+=c[k];
 34             k-=k&-k;
 35         }
 36         return sum;
 37     }
 38     ll query(int l,int r){return query(r)-query(l-1);}
 39 }ta;
 40 void CalPri(){
 41     mu[1]=1;
 42     memset(Is_pri,-1,sizeof(Is_pri));
 43     for(int i=2;i<maxn;i++){
 44         if(Is_pri[i]){
 45             pri[len++]=i;
 46             mu[i]=-1;
 47         }
 48         for(int j=0;j<len&&pri[j]*i<maxn;j++){
 49             Is_pri[pri[j]*i]=false;
 50             mu[pri[j]*i]=-mu[i];
 51             if(i%pri[j]==0){
 52                 mu[pri[j]*i]=0;
 53                 break;
 54             }
 55         }
 56     }
 57 }
 58 void CalFactor(){
 59     for(int i=2;i<maxn;i++){
 60         for(int j=i;j<maxn;j+=i){
 61             if(mu[i])factor[j].push_back(i);
 62         }
 63     }
 64 }
 65 int main(){
 66 //    freopen("e:\\in.txt","r",stdin);
 67     int T;
 68     CalPri();
 69     CalFactor();
 70     scanf("%d",&T);
 71     while(T--){
 72         scanf("%d%d",&n,&m);
 73         ta.init(n);
 74         for(int i=1;i<=n;i++){
 75             scanf("%d",&a[i]);
 76             loca[a[i]]=i;
 77         }
 78         for(int i=1;i<=m;i++){
 79             scanf("%d%d",&l[i],&r[i]);
 80             order[i]=i;
 81         }
 82         int idx=1;
 83         sort(order+1,order+m+1,Cmp);
 84         for(int i=3;i<=n;i++){
 85             while(idx<=m&&r[order[idx]]<i){
 86                 ans[order[idx]]=ta.query(l[order[idx]],r[order[idx]]);
 87                 idx++;
 88             }
 89             cnt=0;
 90             for(int k=2;k*a[i]<=n;k++){
 91                 if(loca[k*a[i]]<i)temp[cnt++]=loca[k*a[i]];
 92             }
 93             sort(temp,temp+cnt);
 94             for(int j=cnt-1;j>=0;j--){
 95                 int t=temp[j],s=a[t]/a[i];
 96                 ll sum=cnt-j-1;
 97                 for(int k=0;k<factor[s].size();k++){
 98                     int q=factor[s][k];
 99                     sum+=num[factor[s][k]]*mu[factor[s][k]];
100                     num[factor[s][k]]++;
101                 }
102                 ta.add(t,sum*a[i]);
103             }
104             for(int j=cnt-1;j>=0;j--){
105                 int t=temp[j],s=a[t]/a[i];
106                 for(int k=0;k<factor[s].size();k++){
107                     num[factor[s][k]]=0;
108                 }
109             }
110         }
111         while(idx<=m){
112             ans[order[idx]]=ta.query(l[order[idx]],r[order[idx]]);
113             idx++;
114         }
115         for(int i=1;i<=m;i++){
116             printf("%lld\n",ans[i]);
117         }
118     }
119     return 0;
120 }

 

转载于:https://www.cnblogs.com/7391-KID/p/7362185.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值