TrickGCD
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 622 Accepted Submission(s): 236
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
* 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
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
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
109+7
Sample Input
1 4 4 4 4 4
Sample Output
Case #1: 17
Source
题意:
给出 A数组,求有多少个数组满足 1≤Bi≤Ai 时 ,全体的gcd大于等于二
题解:
枚举gcd=k 范围是 2 ~ MIN (MIN 表示A数组中最小的数字)
再枚举k的倍数
对于每个 k,在a[i]这个位置上有 a[i] / k 个数能满足条件构成 b[i],只要把每个位置求出来累乘就好了
下面代码累乘的时候,得到了一个 指数,用快速幂处理即可
此时发现有重复现象
需要进行容斥搞一下就行了,然后容易发现使用莫比乌斯函数可以很快的解决
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN=100000+1000;
const int mod=1e9+7;
int cnt[MAXN];
bool check[MAXN];
int primer[MAXN];
int mu[MAXN];
void Moblus()
{
mu[1]=1;
int tot=1;
for(int i=2;i<=MAXN;i++){
if(!check[i]){
primer[tot++]=i;
mu[i]=-1;
}
for(int j=1;j<tot&&i*primer[j]<=MAXN;j++){
check[i*primer[j]]=true;
if(i%primer[j]==0){
mu[i*primer[j]]=0;
break;
}
mu[i*primer[j]]=-mu[i];
}
}
}
ll qmi(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b%2==1)ans=ans*a%mod;
a=(a*a)%mod;
b/=2;
}
return ans;
}
int main()
{
Moblus();
freopen("in.txt","r",stdin);
int n,cases=0,x,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int MIN=INF;
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++){
scanf("%d",&x);
MIN=min(MIN,x);
cnt[x]++;
}
for(int i=1;i<MAXN;i++)
cnt[i]+=cnt[i-1];
ll ans=0,t;
for(int i=2;i<=MIN;i++){
t=1;
for(int j=1;i*j<=100000;j++)
t=t*qmi(j,cnt[(j+1)*i-1]-cnt[j*i-1])%mod;
ans=(ans-t*mu[i]%mod+mod)%mod;
}
printf("Case #%d: %lld\n",++cases,ans);
}
return 0;
}