【组合数学】 HDU 4675 GCD of Sequence

通道

题意:有三个数N, M, K, 然后N个特定序列。  从这特定的序列里必须改变K个数字, 取值范围为 [1,M]。 然后求出各序列的最大公约数为1~M分别多少个

思路:

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

//

const int V = 300000 + 50;
const int inf = 0x7fffffff;
const int mod = 1000000000 + 7;
int n, m, k;
int sum[V];
__int64 ans[V], d[V], e[V];
__int64 Quick_Pow(__int64 a, __int64 b) {
    __int64 res = 1;
    while(b) {
        if(b & 1)
            res = (res * a) % mod;
        b /= 2;
        a = (a * a) % mod;
    }
    return res % mod;
}
__int64 Cal(__int64 n, __int64 k) {
    return (d[n] * e[k] % mod) * e[n - k] % mod;
}
int main() {
    int i, j;
    d[0] = e[0] = 1;
    for(i = 1; i < V; ++i) {
        d[i] = (d[i - 1] * i) % mod;
        e[i] = Quick_Pow(d[i], mod - 2);
    }
    while(~scanf("%d%d%d", &n, &m, &k)) {
        memset(sum, 0, sizeof(sum));
        for(i = 0; i < n; ++i) {
            int temp;
            scanf("%d", &temp);
            sum[temp]++;
        }
        for(i = m; i >= 1; --i) {
            int sum_d = 0;
            for(j = i; j <= m; j += i)
                sum_d += sum[j];
            if(n - sum_d > k) {
                ans[i] = 0;
                continue;
            }
            ans[i] = (Quick_Pow(m / i, n - sum_d) * Quick_Pow(m / i - 1, k - (n - sum_d)) % mod) * Cal(sum_d, k - (n - sum_d)) % mod;
            //减去重复的
            for(j = 2 * i; j <= m; j += i)
                ans[i] = (ans[i] - ans[j] + mod) % mod;
        }
        for(i = 1; i < m; ++i)
            printf("%I64d ", ans[i]);
        printf("%I64d\n", ans[m]);
    }
}
View Code

 

posted @ 2015-08-17 21:40  mithrilhan  阅读(188)  评论(0编辑  收藏  举报