zoukankan      html  css  js  c++  java
  • HDU 6053 TrickGCD 莫比乌斯函数/容斥/筛法

    题意:给出n个数$a[i]$,每个数可以变成不大于它的数,现问所有数的gcd大于1的方案数。其中$(n,a[i]<=1e5)$

    思路:鉴于a[i]不大,可以想到枚举gcd的值。考虑一个$gcd(a_1,a_2,a_3…a_n)=d$,显然每个$a_i$的倍数都满足,有$frac{a_i}{d}$种方案

    那么一个d对答案的贡献为[prod_{i=1}^{min(a)}{lfloorfrac{a_i}{d} floor}    ]

    但是所有的d计入会有重复情况,考虑容斥,对d进行素数分解,发现重复情况就是d的互异素数个数为偶数的,或是素数的指数大于1的。

    然后会发现这情况的系数和莫比乌斯函数定义很像$(-f(d)) = mu(d)=(-1)^k, d={p_1}{p_2}…{p_k}$,$mu(d) = 0,d为非1整数$

    现在我们就要考虑如何快速求得一个d的贡献了,类似筛法的思想,由于a[i]不大,预处理出前缀和,sum[i]代表小于i的数的个数,将按方案数大小分块,累加$cnt^{sum[(cnt+1)*d-1]-sum[cnt*d-1]}$得到结果,乘上容斥系数即可。

    [ ans = sum_{d=1}^{min(a)}{(-mu(d)) sum_{j=1}^{lfloor frac{min(a)}{d} floor}{j^{sum_{i=1}^{n}{[lfloor frac{a_i}{d} floor = j]}}          }}  ]

    也就是把上式j的指数前缀和优化了一下。

    分块优化也是很常见的,和以前的数论组合题已经算简单了,我好鶸鶸鶸鶸鶸鶸阿

    /** @Date    : 2017-07-28 19:30:46
      * @FileName: HDU 6053 莫比乌斯函数 容斥 1009.cpp
      * @Platform: Windows
      * @Author  : Lweleth (SoungEarlf@gmail.com)
      * @Link    : https://github.com/
      * @Version : $Id$
      */
    #include <bits/stdc++.h>
    #define LL long long
    #define PII pair
    #define MP(x, y) make_pair((x),(y))
    #define fi first
    #define se second
    #define PB(x) push_back((x))
    #define MMG(x) memset((x), -1,sizeof(x))
    #define MMF(x) memset((x),0,sizeof(x))
    #define MMI(x) memset((x), INF, sizeof(x))
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int N = 1e5+20;
    const double eps = 1e-8;
    const LL mod = 1e9 + 7;
    
    LL pri[N];
    LL mu[N];
    LL sum[N];
    bool vis[N];
    int c = 0;
    
    void mobius()
    {
        MMF(vis);
        mu[1] = 1;
        for(int i = 2; i < N; i++)
        {
            if(!vis[i])
                pri[c++] = i, mu[i] = -1;
            for(int j = 0; j < c && i * pri[j] < N; j++)
            {
                vis[i * pri[j]] = 1;
                if(i % pri[j])
                    mu[i * pri[j]] = -mu[i];
                else
                {
                    mu[i * pri[j]] = 0;
                    break;
                }
            }
        }
        for(int i = 0; i < N; i++)
        	mu[i] *= -1;
    }
    
    LL fpow(LL x, LL n)
    {
    	LL ans = 1;
    	while(n > 0)
    	{
    		if(n & 1)
    			ans = ans * x % mod;
    		x = x * x % mod;
    		n >>= 1;
    	}
    	return ans;
    }
    
    int n;
    LL a[N];
    
    int main()
    {
    	int icase = 0;
    	int T;
    	cin >> T;
    	mobius();
    	while(T--)
    	{
    		MMF(sum);
    		scanf("%d", &n);
    		LL mi = INF;
    		LL ma = -1;
    		for(int i = 0; i < n; i++)
    		{
    			scanf("%lld", a + i);
    			mi = min(a[i], mi);
    			ma = max(a[i], ma);
    			sum[a[i]]++;
    		}
    		for(int i = 2; i <= ma; i++)
    			sum[i] += sum[i - 1];
    
    		LL ans = 0;
    		for(LL g = 2; g <= mi; g++)
    		{
    			if(mu[g] == 0)
    				continue;
    			LL t = 1;
    			LL cnt = 1;
    			while(true)
    			{
    				int l = min(cnt * g, ma);
    				int r = min((cnt + 1) * g - 1, ma);
    				if(r > l - 1)
    					t = (t * fpow(cnt, sum[r] - sum[l - 1]) % mod + mod) % mod;
    				if(r == ma)
    					break;
    				cnt++;
    			}
    			//cout << t <<endl;
    			ans = (ans + mu[g] * t + mod) % mod;
    		}
    		while(ans < 0)
    			ans += mod;
    		printf("Case #%d: %lld
    ", ++icase, ans);
    	}
        return 0;
    }
    
  • 相关阅读:
    六.初识Mybatis
    python中文资源大全
    阅读《乌云回忆录一》后的一点感慨
    SSH无法连上CentOS7的问题
    [转]sqlmap使用教程
    [转]11种常见sqlmap使用方法详解
    ZVulDrill渗透环境搭建及部分题目writeup
    渗透资源大全-整理
    【洛谷5934】[清华集训2012] 最小生成树(最小割)
    【洛谷3974】[TJOI2015] 组合数学(模拟最大流)
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/7253032.html
Copyright © 2011-2022 走看看