hdu 6102 GCDispower 树状数组+容斥

来源:互联网 发布:2017php应聘要求 编辑:程序博客网 时间:2024/06/06 02:30


GCDispower

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 175    Accepted Submission(s): 87


Problem Description
There is a mysterious organization called GCD. They get a permutation P, permutation is a sequence of length N, only consists of number 1 to N and each number appears only once.
They want to gain magic power from this permutation. For the interval [L, R] they can get power:
i=LRj=i+1Rk=j+1R(gcd(P[i],P[j])==P[k])P[k]
Now they have M queries, for each query can you help them calculate how many power they can get?
 

Input
The first line is an integer T which indicates the case number.
And as for each case, first line is two integer N and M which indicates the length of permutation and number of query.
Next line is N integer which indicate the permutation P
Next M line, for each line is two integer L and R which indicate each query.

Limit
1T100
1N,M100000
1PiN, for any pair (i,j)PiPj
1LiRiN

About 95% test case: 1N1000
Other test case: 1N100000
 

Output
As for each case, you need to output M integer which indicate the answer of each query.
 

Sample Input
23 13 2 11 36 36 5 4 3 2 11 62 63 5
 

Sample Output
1850
 

Source
2017 Multi-University Training Contest - Team 6
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  6107 6106 6105 6104 6103 
参考的博客:http://blog.csdn.net/creatorx/article/details/77106506

题意:给你n个数,m次询问(l,r)的价值,l到r的价值定义为gcd(p[i],p[j])==p[k]的对数*p[k](i,j,k均在范围内且互不相等)。

思路:根据官方题解,题目可以转化为求l到r,p[i]/p[k]和p[j]/p[k]互质的对数*p[k],所以我们可以固定右端点r,求出所有左端点的答案。做法如下:先枚举右端点r,再用O(logn)的时间记录坐标<r并且是p[r]的倍数的位置,再用O(logn*logn)的时间从小到大排序。再把这些数从右往左扫一遍,假设当前位置为i,每次可以通过容斥求出i+1~r-1有多少个数和他互质,从而更新某段区间的答案,这里用树状数组或者线段树更新,具体方法看代码,不好说明。最后对每个r操作完即可查询右端点为r的询问的答案,记录一下就好了。

下面给代码:

#include <bits/stdc++.h>   using namespace std;  #define maxn 100005#define inf 0x3f3f3f3ftypedef long long LL;const int mod=1e9+7;vector<pair<int,int> >status[maxn];vector<pair<int,int> >query[maxn];vector<int>prime[maxn];int vis[maxn],p[maxn],index[maxn],temp[maxn],now[maxn];LL tree[maxn],ans[maxn];int n,m;#define lowerbit(x) x&(-x)void add(int pos,LL val){while(pos<=n){tree[pos]+=val;pos+=lowerbit(pos);}}void update(int l,int r,LL val){if(l-1>0)add(l-1,-val);add(r,val);}LL get(int l,int r){LL ans=0;while(r){ans+=tree[r];r-=lowerbit(r);}l--;while(l){ans-=tree[l];l-=lowerbit(l);}return ans;}LL getans(int x){LL cnt=0;for(int i=0;i<status[x].size();i++)cnt+=now[status[x][i].first]*status[x][i].second;return cnt;}void insert(int x,int val){for(int i=0;i<status[x].size();i++)now[status[x][i].first]+=val;}void init(){for(int i=2;i<maxn;i++)if(!vis[i])for(int j=i;j<maxn;j+=i){vis[j]=1;prime[j].push_back(i);}for(int i=1;i<maxn;i++)for(int j=0;j<(1<<prime[i].size());j++){status[i].push_back(make_pair(1,1));for(int k=0;k<prime[i].size();k++){if((1<<k)&j){status[i][j].first*=prime[i][k];status[i][j].second*=-1;}}}}int main(){init();int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);memset(tree,0,sizeof(tree));for(int i=1;i<=n;i++){scanf("%d",&p[i]);index[p[i]]=i;query[i].clear();}for(int i=0;i<m;i++){int l,r;scanf("%d%d",&l,&r);query[r].push_back(make_pair(i,l));}for(int i=1;i<=n;i++){int length=0;for(int j=p[i]*2;j<=n;j+=p[i])if(index[j]<i)temp[length++]=index[j];sort(temp,temp+length);LL sum=0;for(int j=length-1;j>=0;j--){sum+=getans(p[temp[j]]/p[i])*p[i];insert(p[temp[j]]/p[i],1);if(j>0)update(temp[j-1]+1,temp[j],sum);elseupdate(1,temp[0],sum);}for(int j=0;j<length;j++)insert(p[temp[j]]/p[i],-1);for(int j=0;j<query[i].size();j++)ans[query[i][j].first]=get(query[i][j].second,i);}for(int i=0;i<m;i++)printf("%lld\n",ans[i]);}}