hdu4675 GCD of Sequence 莫比乌斯+组合数学

/**
题目:hdu4675 GCD of Sequence
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675
题意:给定n个数的a数组,以及m,k;
构造满足1<=bi<=m,和a数组恰好k个位置ai!=bi的b数组。
输出b数组所有数的gcd分别为1~m的数组个数。

思路:

f(n)表示gcd==n的数组个数。
g(n)表示gcd是n的倍数的数组个数。

f(n) = sigma[n|d]mu[d/n]*g(d);

如何求g(d)呢?

如果没有k,显然是g(d)=(M/d)^n;

可问题是存在k..... 必须满足所有的数都是d的倍数。 且有k个bi与ai不相同。

有M/d个数是d的倍数。 如果a数组有cnt个d的倍数。

那么剩下的n-cnt(如果n-cnt>k那么无解)个数必须变成d的倍数,有(M/d)^(n-cnt)种情况;

还剩下k-(n-cnt)个数需要从a数组cnt个是d的倍数中改变。有C(cnt,k-(n-cnt))*(M/d-1)^(k-(n-cnt));

所以g(d) = (M/d)^(n-cnt)*C(cnt,k-(n-cnt))*(M/d-1)^(k-(n-cnt)); (n-cnt<=k)
    g(d) = 0; (n-cnt>k)

    C(n,m) = n!/((n-m)!*m!)
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
#define ms(x,y) memset(x,y,sizeof x)
typedef pair<int, int> P;
const LL INF = 1e10;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 100;
int prime[maxn], tot, not_prime[maxn];
int mu[maxn], cnt[maxn];
LL fac[maxn], inv[maxn], f[maxn];
int n, m, k;
void init()
{
    inv[0] = inv[1] = 1;
    for(int i = 2; i < maxn; i++){
        inv[i] = (mod-mod/i)*inv[mod%i]%mod;
    }
    fac[0] = fac[1] = 1;
    for(int i = 2; i < maxn; i++){
        fac[i] = fac[i-1]*i%mod;
        inv[i] = inv[i]*inv[i-1]%mod;
    }
}
LL Pow(LL x,int y)
{
    LL p = 1;
    while(y){
        if(y&1) p = p*x%mod;
        x = x*x%mod;
        y>>=1;
    }
    return p;
}
void mobius()
{
    mu[1] = 1;
    tot = 0;
    for(int i = 2; i < maxn; i++){
        if(!not_prime[i]){
            mu[i] = -1;
            prime[++tot] = i;
        }
        for(int j = 1; prime[j]*i<maxn; j++){
            not_prime[prime[j]*i] = 1;
            if(i%prime[j]==0){
                mu[prime[j]*i] = 0;
                break;
            }
            mu[prime[j]*i] = -mu[i];
        }
    }
}

LL get(int d)
{
    if(n-cnt[d]>k) return 0;
    return Pow((LL)m/d,n-cnt[d])*fac[cnt[d]]%mod*inv[n-k]%mod*inv[k-n+cnt[d]]%mod*Pow((LL)m/d-1,k-n+cnt[d])%mod;
}
int main()
{
    //freopen("YYnoGCD.in","r",stdin);
    //freopen("YYnoGCD.out","w",stdout);
    //freopen("in.txt","r",stdin);
    int T;
    mobius();
    init();
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        ms(cnt,0);
        int x;
        for(int i = 1; i <= n; i++){
            scanf("%d",&x);
            cnt[x]++;
        }
        for(int i = 1; i <= m; i++){
            for(int j = 2*i; j <= m; j+=i){
                cnt[i] += cnt[j];
            }
        }
        ms(f,0);

        for(int i = 1; i <= m; i++){
            for(int j = i; j <= m; j+=i){
                f[i] = (f[i]+mu[j/i]*get(j)+mod)%mod;
            }
        }
        for(int i = 1; i < m; i++) printf("%lld ",f[i]);
        printf("%lld\n",f[m]);
    }
    return 0;
}
时间: 2024-11-05 16:24:14

hdu4675 GCD of Sequence 莫比乌斯+组合数学的相关文章

hdu4675 GCD of Sequence

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675 题意: 给定一个长度为n的序列a,且 1<=a[i]<=m,求分别有多少个序列b,使得GCD(b[1],b[2],...b[n])=x (1<=x<=m),且正好有k个b[i]!=a[i]. 分析: 莫比乌斯反演,主要是确定F(x). 用F(x)表示gcd为x的倍数的方案数,f(x)表示gcd为x的方案数. 先考虑F(d)怎么计算.可以把a数组中的数分成两类,第一类是必须对应下标

hdu4908 &amp; BestCoder Round #3 BestCoder Sequence(组合数学)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4908 BestCoder Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 618    Accepted Submission(s): 214 Problem Description Mr Potato is a code

HDU 4908 BestCoder Sequence(组合数学)

HDU 4908 BestCoder Sequence 题目链接 题意:给定一个序列,1-n的数字,选定一个作为中位数m,要求有多少连续子序列满足中位数是m 思路:组合数学,记录下m左边和右边一共有多少种情况大于m的数字和小于n数组的差,然后等于左边乘右边所有的和,然后最后记得加上左右两边差为0的情况. 当时也是比较逗,还用树状数组去搞了,其实完全没必要 代码: #include <cstdio> #include <cstring> #define lowbit(x) (x&am

HDU 4675 GCD of Sequence(莫比乌斯反演 + 打表注意事项)题解

题意: 给出\(M\)和\(a数组\),询问每一个\(d\in[1,M]\),有多少组数组满足:正好修改\(k\)个\(a\)数组里的数使得和原来不同,并且要\(\leq M\),并且\(gcd(a_1,a_2,\dots,a_n)=d\). 思路: 对于每一个\(d\),即求\(f(d)\):修改\(k\)个后\(gcd(a_1,a_2,\dots,a_n)=d\)的对数. 那么假设\(F(d)\):修改\(k\)个后\(gcd(a_1,a_2,\dots,a_n)\)是\(d\)倍数的对数.

ACM学习历程—ZOJ 3868 GCD Expectation(莫比乌斯 || 容斥原理)

Description Edward has a set of n integers {a1, a2,...,an}. He randomly picks a nonempty subset {x1, x2,…,xm} (each nonempty subset has equal probability to be picked), and would like to know the expectation of [gcd(x1, x2,…,xm)]k. Note that gcd(x1, 

bnu——GCD SUM (莫比乌斯反演)

题目:GCD SUM 题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=39872 算法:莫比乌斯反演.优化 1 #include<stdio.h> 2 #define N 100001 3 typedef long long LL; 4 bool pri[N]={0}; 5 int prim[N],po=0; 6 int mu[N]; 7 LL f[N],ff[N]; //缩短时间 8 /* 9 莫比乌斯函数mu[i]的定义: 10 1. 如

【Project Euler】530 GCD of Divisors 莫比乌斯反演

[题目]GCD of Divisors [题意]给定f(n)=Σd|n gcd(d,n/d)的前缀和F(n),n=10^15. [算法]莫比乌斯反演 [题解]参考:任之洲数论函数.pdf 这个范围显然杜教筛也是做不了的,而且考虑直接化简f(n)也遇到了困难,所以考虑将前缀和的Σ一起化简. $$F(n)=\sum_{i=1}^{n}\sum_{d|i}(d,\frac{i}{d})$$ 这一步很常见的是第一重改为枚举倍数,但这样化简后面就推不下去了. 这道题必须最后转成$\sigma_0(n)$才

SPOJ - PGCD Primes in GCD Table(莫比乌斯反演)

http://www.spoj.com/problems/PGCD/en/ 题意: 给出a,b区间,求该区间内满足gcd(x,y)=质数的个数. 思路: 设f(n)为 gcd(x,y)=p的个数,那么F(n)为 p | gcd(x,y)的个数,显然可得F(n)=(x/p)*(y/p). 这道题目因为可以是不同的质数,所以需要枚举质数, 但是这样枚举太耗时,所以在这里令t=pk, 这样一来的话,我们只需要预处理u(t/p)的前缀和,之后像之前的题一样分块处理就可以了. 1 #include<ios

hdu4908 &amp;amp; BestCoder Round #3 BestCoder Sequence(组合数学)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4908 BestCoder Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 618    Accepted Submission(s): 214 Problem Description Mr Potato is a code