2017 多校2 hdu 6053 TrickGCD

2017 多校2 hdu 6053 TrickGCD

题目:

You are given an array \(A\) , and Zhu wants to know there are how many different array \(B\) satisfy the following conditions?

  • \(1≤B_i≤A_i\)
  • For each pair(\(l , r) (1≤l≤r≤n) , gcd(bl,bl+1...br)≥2\)

Input

The first line is an integer \(T(1≤T≤10)\) describe the number of test cases.

Each test case begins with an integer number n describe the size of array \(A\).

Then a line contains \(n\) numbers describe each element of \(A\)

You can assume that \(1≤n,A_i≤10^{5}\)

Output

For the \(k\)th test case , first output "Case #\(k\): " , then output an integer as answer in a single line . because the answer may be large , so you are only need to output answer mod \(10^{9}+7\)

思路:

枚举\(g = gcd(b_1,b_2,....,b_n)\),
那么\(gcd为g\)的倍数的答案就是\(\prod_{i=1}^{n}\frac{A_i}{g}\)
每次暴力计算是不行的,想到一个数在\(g到2g-1\)除以g结果是不变的
所以可以预处理区间数字个数的前缀和,\(O(nlogn)\)类似素数筛法预处理出每个\(g\)的答案
现在要计算\(gcd为g\)的答案,我们从大到小枚举,同时更新它的约数的答案,就可以保证不重复了
从小到大枚举过去就要用到莫比乌斯函数去计算了
\(令F(i)为gcd为i的倍数的方案数,f(i)为gcd为i的方案数\)
\(F(i) = \sum_{i|d}^{}{f(d)} \rightarrow f(i) = \sum_{i|d}u(\frac{d}{i})F(d)\)
代码贴的是比赛时过的姿势

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
vector<int> v[N];
int n;
int sum[N],ans[N];
void init(){
    for(int i = 2;i < N;i++){
        for(int j = i;j < N;j+=i) v[j].push_back(i);
    }
}
int qpow(int x,int y){
    int ans = 1;
    while(y){
        if(y&1) ans = 1LL* ans * x % mod;
        x = 1LL * x * x % mod;
        y >>= 1;
    }
    return ans;
}
int main(void)
{
    init();
    int T, x;
    int cas = 1;
    cin>>T;
    while(T--){
        memset(sum, 0, sizeof(sum));
        scanf("%d",&n);
        int mi = N;
        for(int i = 1;i <= n;i++) {
            scanf("%d",&x);
            mi = min(x,mi);
            sum[x]++;
        }
        for(int i = 1;i < N;i++) sum[i]+=sum[i-1];
        for(int i = 2;i <= mi;i++){
            ans[i] = 1;
            for(int j = i;j < N;j+=i){
                int l = j + i - 1 > N - 1?N-1:j + i - 1;
                ans[i] = 1LL * ans[i] * qpow(j / i,sum[l] - sum[j - 1]) % mod;
            }
        }
        int res = 0;
        for(int i = mi;i >= 2;i--){
            res = (res + ans[i])%mod;
            for(int j = 0;j < v[i].size();j++) ans[v[i][j]] = (ans[v[i][j]] - ans[i] + mod)%mod;
        }
        printf("Case #%d: %d\n",cas++,res);
    }
    return 0;
}
posted @ 2017-08-01 11:14  jiachinzhao  阅读(156)  评论(0编辑  收藏  举报