HDU 6053 ( TrickGCD ) 分块+容斥
Posted liylho
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6053 ( TrickGCD ) 分块+容斥相关的知识,希望对你有一定的参考价值。
TrickGCD
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3401 Accepted Submission(s): 1268
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 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
思路:枚举gcd ,对于当前的i,分区间地计算出gcd为i倍数的数列总数,之后利用容斥来减掉重复的部分,要保证每次减掉都是确定的倍数因此要倒着减。
代码:
1 #include<bits/stdc++.h> 2 #define db double 3 #define ll long long 4 #define ci(x) scanf("%d",&x) 5 #define cd(x) scanf("%lf",&x) 6 #define cl(x) scanf("%lld",&x) 7 #define pi(x) printf("%d\n",x) 8 #define pd(x) printf("%f\n",x) 9 #define pl(x) printf("%lld\n",x) 10 #define fr(i,a,b) for(int i=a;i<=b;i++) 11 using namespace std; 12 const int N=1e5+5; 13 const int mod=1e9+7; 14 const int MOD=mod-1; 15 const db eps=1e-10; 16 const int inf = 0x3f3f3f3f; 17 ll a[N]; 18 ll sum[N]; 19 ll qpow(ll x,ll n) 20 { 21 ll ans=1;x%=mod; 22 for(;n>0;n>>=1){if(n&1) ans=(ans*x)%mod;x=x*x%mod;} 23 return ans; 24 } 25 int main() 26 { 27 // ios::sync_with_stdio(false); 28 // cin.tie(0); 29 int t; 30 ci(t); 31 for(int ii=1;ii<=t;ii++) 32 { 33 int n,x,ma=-N,mi=N; 34 memset(sum,0,sizeof(sum)); 35 ci(n); 36 for(int i=0;i<n;i++) 37 ci(x),sum[x]++,ma=max(ma,x),mi=min(mi,x); 38 for(int i=1;i<=ma;i++) sum[i]+=sum[i-1];//统计小于等于i的数字的个数 39 for(int i=2;i<=mi;i++){//从2~mi枚举gcd 40 a[i]=1; 41 for(int j=i;j<=ma;j+=i){//分区间计算 42 int c; 43 if(i+j-1<=ma) c=sum[i+j-1]-sum[j-1]; 44 else c=sum[ma]-sum[j-1]; 45 if(!c) continue; 46 a[i]=(a[i]*qpow(j/i,c))%mod; 47 } 48 } 49 ll ans=0; 50 for(int i=mi;i>=2;i--) 51 { 52 for(int j=i+i;j<=mi;j+=i) a[i]=(a[i]-a[j])%mod;//减掉确定的倍数 53 a[i]=(a[i]+mod)%mod; 54 ans=(ans+a[i])%mod; 55 } 56 printf("Case #%d: %lld\n",ii,ans); 57 } 58 }
以上是关于HDU 6053 ( TrickGCD ) 分块+容斥的主要内容,如果未能解决你的问题,请参考以下文章