TrickGCD
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2523 Accepted Submission(s): 965
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≤1e5
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≤1e5
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 1e9+7
Sample Input
1
4
4 4 4 4
Sample Output
Case #1: 17
题目大意:有数组A,根据1<=Bi<=Ai,且对于任意1<=l<=r<=n, gcd(Bl,Bl+1...Br)≥2 构造B数列
思路:B的最小值一定不会大于A的最小值,所以gcd(B1,B2,...,Bn)一定不大于A的最小值,那么我们可以求出A的最小值,对gcd为质数的情况求和,利用容斥原理减去重复的情况。在计算重复情况时,发现对于gcd是奇数个质数的乘积时是加,偶数个时是减,与莫比乌斯函数相反,那么就可以借助莫比乌斯函数求和。这里暴力求和会超时,问了学长之后才知道分桶计算可以快很多,涨姿势了。
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 typedef long long LL; 6 const int MAXN=1e5+10; 7 const int MOD=1e9+7; 8 LL miu[MAXN],primes[MAXN],tot=0; 9 bool isprime[MAXN]; 10 int a[MAXN],sum[MAXN]; 11 int maxx=0,minn=MAXN; 12 void getmiu() 13 { 14 memset(isprime, 0, sizeof((isprime))); 15 miu[1]=1; 16 for(int i=2;i<MAXN;i++){ 17 if(isprime[i]==false) 18 { 19 miu[i]=-1; 20 primes[++tot]=i;//cout<<'*'<<endl; 21 } 22 for(int j=1;j<=tot;j++){ 23 if(i*primes[j]>=MAXN) break; 24 isprime[i*primes[j]]=1; 25 if(i%primes[j]==0){ 26 miu[i*primes[j]]=0; 27 break; 28 } 29 miu[i*primes[j]]=-miu[i]; 30 } 31 } 32 33 34 for(int i=1;i<MAXN;i++) miu[i]=-miu[i]; 35 } 36 LL quick_pow(LL a, LL p) 37 { 38 int res=1; 39 while(p) 40 { 41 if(p&1) res=a*res%MOD; 42 a=a*a%MOD; 43 p>>=1; 44 } 45 return res; 46 } 47 int solve() 48 { 49 LL i,j,k,p; 50 LL ans=0; 51 for(int i=2;i<=minn;i++){ 52 if(!miu[i]) continue; 53 LL res=1; 54 j=min(i, maxx), k=min((i<<1)-1, maxx); 55 for(p=1; ;p++) 56 { 57 if(sum[k]-sum[j-1]) 58 res=res*quick_pow(p, sum[k]-sum[j-1])%MOD; 59 if(k==maxx) break; 60 j+=i; 61 k+=i; 62 if(k>maxx) k=maxx; 63 } 64 ans+=miu[i]*res; 65 if(ans>MOD) ans-=MOD; 66 if(ans<0) ans+=MOD; 67 } 68 return ans%MOD; 69 70 } 71 int main() 72 { 73 int T,n,t=0; 74 getmiu(); 75 scanf("%d", &T); 76 //cout<<'*'<<endl; 77 while(T--) 78 { 79 scanf("%d", &n); 80 maxx=0,minn=MAXN; 81 memset(sum, 0, sizeof(sum)); 82 for(int i=0;i<n;i++){ 83 scanf("%d", &a[i]); 84 sum[a[i]]++; 85 maxx=max(a[i], maxx); 86 minn=min(a[i], minn); 87 } 88 for(int i=1;i<=maxx;i++) sum[i]+=sum[i-1]; 89 LL res=solve(); 90 printf("Case #%d: %lld ", ++t, res); 91 } 92 }