【 hdu 6053】 TrickGCD 【数论 容斥 + 莫比乌斯函数 】

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

  • 1≤Bi≤Ai
  • 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,Ai≤105

Output
For the kth 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 109+7

Sample Input
1
4
4 4 4 4

Sample Output
Case #1: 17

Source
2017 Multi-University Training Contest - Team 2

题解链接
代码

#include<bits/stdc++.h>
#define LL long long 
using namespace std;
const int mod = 1e9+7;
const int MAXN = 100200;
const int inf  =  0x3f3f3f3f;
bool su[MAXN]; 
int prime[MAXN],miu[MAXN];
void init(){
    int cnt = 0;
    miu[1] = 1;
    for(LL i = 2; i < MAXN; i++){
        if(!su[i]){
            prime[cnt++] = i;
            miu[i] = -1;
        }
        for(LL j = 0; j < cnt && i*prime[j] < MAXN; j++){
            su[i*prime[j]] = 1;
            if(i % prime[j])
                miu[i*prime[j]] = -miu[i];
            else{
                miu[i*prime[j]] = 0;
                break;
            }
        }
    }
}

inline LL qp(LL a,LL b){
    LL s=1,base=a%mod;
    while(b){
        if(b&1) s=s*base%mod;
        base=base*base%mod;
        b>>=1;   
    } 
    return s;
}

int num[MAXN],suma[MAXN*2];

int main(){
    int t,ncase = 1,n,v,maxa,mina;
    scanf("%d",&t);
    init();
    while(t--){
        LL ans = 0;maxa = -inf,mina = inf;
        scanf("%d",&n);
        memset(num,0,sizeof(num));
        for(int i = 1;i <= n;i++){
            scanf("%d",&v);
            num[v]++;
            mina = min(mina,v);maxa = max(maxa,v);
        }
        for(int i = 1;i <= maxa*2;i++){
            suma[i] = suma[i-1] + num[i];
        }
        LL temp = 1;
        for(int i = 2;i <= mina;i++){
            temp = 1;
            for(int j = 1;j*i <= maxa;j++){
                temp *= qp(j,(suma[i*j+i-1]-suma[i*j-1]));
                temp %= mod;
            }
            ans -= miu[i]*temp;ans %= mod;
        }
        printf("Case #%d: %lld\n",ncase++,(ans+mod)%mod);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值