TrickGCD————(hdu6053)2017多校(莫比乌斯容斥)

本文介绍了一道算法题目,目标是找出满足特定条件的数列B的所有可能组合。通过对最小公倍数的计算及莫比乌斯函数的应用,文章详细阐述了解题过程,并提供了完整的C++代码实现。
Problem Description
You are given an array A , and Zhu wants to know there are how many different array B satisfy the following conditions?

1BiAi
* For each pair( l , r ) (1lrn) , gcd(bl,bl+1...br)2
 

Input
The first line is an integer T(1T10) 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 1n,Ai105
 

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
题意:给出一个数列,然后让你求出另一个数列有多少种可能;
另一个数列满足数列gcd(b1,b2,……,bn)>=2而且对应的bi<=ai;
解题思路:从2开始枚举到min(a1,a2……,an),然后计算含有这个因子的数出现的个数就是
然后利用快速幂计算,然后会有重复计算,利用莫比乌斯容斥;
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long ll; ll mu[100005],cas=1; ll num[200005]; int a[100005]; ll mod=1e9+7; void mobius(ll mn) {     mu[1]=1;     for(ll i=1;i<=mn;i++){         for(ll j=i+i;j<=mn;j+=i){             mu[j]-=mu[i];         }     } } ll  Pow(ll x,ll n) {     ll res=1;     while(n>0)     {         if(n&1)         res=res*x%mod;         x=x*x%mod;         n>>=1;     }     return res; } int main() {     int T,cas;     scanf("%d",&T);     cas=0;     mobius(100000);     while(T--)     {         cas++;         int n;         scanf("%d",&n);         memset(num,0,sizeof(num));         int minn=100005;         for(int i=1;i<=n;i++)         {             scanf("%d",&a[i]);             num[a[i]]++;             minn=min(a[i],minn);         }         for(int i=1;i<=200000;i++)         num[i]+=num[i-1];         ll sum=0;         for(int i=2;i<=minn;i++)         {             ll su=1;             for(int j=1;i*j<=100000;j++)             {                 su=(su*Pow(j,num[i*(1+j)-1]-num[i*j-1]))%mod;//好好想一想在这里             }             sum=(sum-(mu[i]*su)%mod+mod)%mod;         }         printf("Case #%d: %lld\n",cas,sum);     }     return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值