zoukankan      html  css  js  c++  java
  • HDU 6102

    个人感觉题解的复杂度很玄,参不透,有没有大佬讲解一下- -

    /*
    HDU 6102 - GCDispower [ 数论,树状数组]  |  2017 Multi-University Training Contest 6
    题意:
    	给定排列 a[N], M 组 L,R
    	求解 ∑ [ L <= i < j < k <= R ] [ GCD(a[i], a[j]) == a[k] ] * a[k]
    	限制:N, M <= 1e5
    分析:
    	数论角度一般考虑枚举 k,由于是区间询问,且贡献有可加性,考虑对每个L,将[L, R-1] 推到 [L, R]
    	故对于每一个R, 枚举 a[R] 倍数 a[i] (i < R)
    		再对每一个 a[i] , 求得满足 i < j < R && GCD(a[i], a[j]) == a[R] 的个数
    			即 GCD(a[i]/a[R], a[j]/a[R]) == 1 的个数
    		此时对于 L ∈ [1,i-1] 的区间,贡献 = 所得个数 * a[R] , 这部分用区间更新可以完成
    	
    	求 GCD(a[i]/a[R], a[j]/a[R]) == 1 的 j 的个数,用容斥原理
    		a[j]是a[R]的倍数的总个数 - a[j]与a[i]不互质的个数
    	=	a[j]是a[R]的倍数的总个数 - a[j] 是 a[i] 的 1个质因子之积的倍数的个数
    								 + a[j] 是 a[i] 的 2个质因子之积的倍数的个数
    								 ...	
    								 + (-1)^k * a[j] 是 a[i] 的 k个质因子之积的倍数的个数
    	所以预处理每个数所有质因子之积,然后容斥的参数 μ = -1^(k) 可以用莫比乌斯函数
    	具体处理时,可以维护每个质因子之积的倍数,每处理一个 a[i] , 就将它的每个质因子之积的倍数个数+1
    	
    	复杂度: 
    		预处理 O(n+n^1.5)
    		枚举 R 和 a[i] 均摊 O(nlog(n)), 枚举 a[i] 的因子容斥 O(n^0.5)
    		区间查询,更新 O(log(n))
    		总复杂度 : O(n + n^1.5 + T * n * log(n)*(n^0.5 + log(n)))
    		
    	不过由于枚举因子时枚举的是非完全平方数,不足n^0.5,可能优化下来就 n*log(n)^2 了(???)
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    const int N = 100005;
    bool notp[N];
    int prime[N], pnum, mu[N];
    vector<int> fac[N];
    void Mobius() {
    	memset(notp, 0, sizeof(notp));
    	mu[1] = 1;
    	for (int i = 2; i < N; i++) {
    		if (!notp[i]) prime[++pnum] = i, mu[i] = -1;
    		for (int j = 1; prime[j]*i < N; j++) {
    			notp[prime[j]*i] = 1;
    			if (i%prime[j] == 0) {
    				mu[prime[j]*i] = 0;
    				break;
    			}
    			mu[prime[j]*i] = -mu[i];
    		}
    	}
    	for (int i = 1; i < N; i++)
            for (int j = 1; j*j <= i; j++) {
                if (j*j == i && mu[j]) fac[i].push_back(j);
                else if (i%j == 0) {
                    if (mu[j]) fac[i].push_back(j);
                    if (mu[i/j]) fac[i].push_back(i/j);
                }
            }
    }
    int t, n, m, a[N], vis[N];
    struct Query {
        int l, id;
    };
    vector<Query> Q[N];
    LL ans[N];
    LL c[N];
    void modify(int x, int num) {
        if (x == 0) return;
        while (x <= n) c[x] += num, x += x&-x;
    }
    LL sum(int x){
        LL s = 0;
        while (x) s += c[x], x -= x&-x;
        return s;
    }
    int cnt[N];
    void addCnt(int x) {
        for (auto& y : fac[x]) cnt[y]++;
    }
    void solve(int l, int x, int k)
    {
        int num = 0;
        for (auto& y : fac[x])
            num += mu[y] * cnt[y];
        modify(1, k*num);
        modify(l+1, -k*num);
        addCnt(x);
    }
    vector<int> mul;
    bool cmp(int a, int b) {
        return a > b;
    }
    void init() {
        memset(vis, 0, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        memset(c, 0, sizeof(c));
        for (int i = 0; i < N; i++) Q[i].clear();
    }
    int main()
    {
        Mobius();
        scanf("%d", &t);
        while (t--)
        {
            init();
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
            for (int i = 1; i <= m; i++)
            {
                int l, r; scanf("%d%d", &l, &r);
                Q[r].push_back(Query{l, i});
            }
            for (int i = 1; i <= n; i++)
            {
                mul.clear();
                for (int j = 2*a[i]; j <= n; j += a[i])
                    if (vis[j]) mul.push_back(vis[j]);
                sort(mul.begin(), mul.end(), cmp);
                for (auto & l : mul) solve(l, a[l]/a[i], a[i]);
                for (int j = 0; j <= n/a[i]; j++) cnt[j] = 0;
                vis[a[i]] = i;
                for (auto& x : Q[i]) ans[x.id] = sum(x.l);
            }
            for (int i = 1; i <= m; i++) printf("%lld
    ", ans[i]);
        }
    }
  • 相关阅读:
    简单实现vue列表点击某个高亮显示
    vue中子组件直接修改父组件prop属性bug
    Java基础——关于接口和抽象类的几道练习题
    Eclipse中导入外部jar包步骤
    Java基础——关于jar包的知识
    Java基础——关于访问权限的一道例题
    Java基础——抽象类和接口
    Java基础——多态
    Java基础——继承
    三个案例,解读静态代码块和构造代码块
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/7346776.html
Copyright © 2011-2022 走看看