链接: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 ",ans[i]); 117 } 118 } 119 return 0; 120 }