zoukankan      html  css  js  c++  java
  • HDU-4676 Sum Of Gcd 莫队+欧拉函数

    题意:给定一个11~nn的全排列AA,若干个询问,每次询问给出一个区间[l,r][l,r],要求得出li<jr  gcd(Ai,Aj)的值。

    解法:这题似乎做的人不是很多,蒟蒻当然不会做只能看题解了qwq,目前看到一个比较好的题解是https://blog.csdn.net/Maxwei_wzj/article/details/79355887

    没什么好说的,首先必须先推式子。

     那么这一坨东西到底是什么意思呢?其实就是对于每个数d,sigma[d|ai][d|aj] 是从区间[l,r]中选两个数且都有约数d的方案数,然后phi(d)乘以这个方案数,对所有的d求和就是答案了。

    然后问题是怎么求从区间[l,r]中选两个数且都有约数d的方案数?考虑[l,r]中的数存在约数d的数个数为c[d],那么显然方案数就是c[d]*(c[d]-1)/2。那么问题又变成了怎么快速维护[l,r]中的数存在约数d的数个数呢?对于这题只有询问的题目我们可以考虑使用莫队算法:先预处理每个数的约数,然后每增加/减少一个数就枚举它的所有约数计算贡献即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=2e4+10,B=233;
    #define bel(x) ((x-1)/B+1)
    int n,m,a[N]; LL sum,c[N],ans[N];
    struct query{
        int id,l,r;
        bool operator < (const query &rhs) const {
            return bel(l)==bel(rhs.l) ? r<rhs.r : l<rhs.l;  //询问排序顺序 
        }
    }q[N];
    
    bool notp[N];
    int pnum, p[N], phi[N];
    vector<int> fac[N];
    void prework(int n) {
        memset(notp, 0, sizeof notp); pnum = 0;
        phi[1]=1;
        for (int i = 2; i <= n; i++) {
            if (!notp[i]) {
                p[pnum++] = i;
                phi[i] = i - 1;
            }
            for (int j = 0; j < pnum && i * p[j] <= n; j++) {
                int k = i * p[j]; notp[k] = 1;
                if (i % p[j] == 0) {
                    phi[k] = phi[i] * p[j];
                    break;
                }
                phi[k] = phi[i] * (p[j] - 1);
            }
        }
        for (int i=1;i<=n;i++)
            for (int j=i;j<=n;j+=i)
                fac[j].push_back(i);
    }
    
    void add(int x) {  //添加操作 
        for (int i=0;i<fac[x].size();i++) {
            int y=fac[x][i];
            sum+=c[y]*phi[y];
            c[y]++;
        }
    }
    
    void del(int x) {  //删除操作 
        for (int i=0;i<fac[x].size();i++) {
            int y=fac[x][i];
            c[y]--;
            sum-=c[y]*phi[y];
        }
    }
    
    void solve() {  //莫队算法 
        int pl=1,pr=0; sum=0;
        for (int i=1;i<=m;i++) {
            while (pl<q[i].l) del(a[pl++]);
            while (pl>q[i].l) add(a[--pl]);
            while (pr<q[i].r) add(a[++pr]);
            while (pr>q[i].r) del(a[pr--]);
            ans[q[i].id]=sum;
        }
    }
    
    int main()
    {
        prework(20000);
        int T,cas=0; cin>>T;
        while (T--) {
            scanf("%d",&n);
            for (int i=1;i<=n;i++) scanf("%d",&a[i]);
            scanf("%d",&m);
            for (int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
            sort(q+1,q+m+1);
            for (int i=1;i<=n;i++) c[i]=0;
            solve();
            printf("Case #%d:
    ",++cas);
            for (int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    973. K Closest Points to Origin
    919. Complete Binary Tree Inserter
    993. Cousins in Binary Tree
    20. Valid Parentheses
    141. Linked List Cycle
    912. Sort an Array
    各种排序方法总结
    509. Fibonacci Number
    374. Guess Number Higher or Lower
    238. Product of Array Except Self java solutions
  • 原文地址:https://www.cnblogs.com/clno1/p/11600392.html
Copyright © 2011-2022 走看看