题意:给出长度为n的A数列,问是否存在一个b数列,1<=bi<=ai,对于B数列的任意区间的gcd都>=2;
思路:枚举每一个gcd(2--100000),然后将其分成长度为gcd的段,如当前gcd为3,我们可以分为0-2,3-5,6-8....,对于第一段如果存在的话,就代表组成不了gcd为3的了,第二段可以组成gcd为3的,第3段可以组成gcd为3,为6,所以num[i]里面有gcd为i,2*i,3*i....的所有总和,最后去个重,
PS:我徐巨巨还是强的呀
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll mod=1e9+7; 5 const int N=1e5+10; 6 7 ll a[N],sum[N]; 8 ll num[N],dp[N]; 9 10 ll hh(ll x,ll y){ 11 ll s=1; 12 while(y){ 13 if(y&1) s=s*x%mod; 14 x=x*x%mod; 15 y/=2; 16 } 17 return s; 18 } 19 20 int main(){ 21 int t; 22 int k=1; 23 scanf("%d",&t); 24 while(t--){ 25 int n; 26 memset(a,0,sizeof(a)); 27 memset(sum,0,sizeof(sum)); 28 memset(num,0,sizeof(num)); 29 scanf("%d",&n); 30 ll x; 31 for(int i=1;i<=n;i++){ 32 scanf("%d",&x);a[x]++; 33 } 34 for(int i=1;i<=100020;i++) 35 sum[i]=sum[i-1]+a[i]; 36 ll s; 37 for(int i=2;i<=100000;i++){ 38 num[i]=1; 39 for(int j=0;j<=100000;j+=i){//j为当前段的起点// 40 if(j+i-1>100000) s=sum[100000]-sum[j-1];//s为这一段的个数// 41 else if(j==0) s=sum[j+i-1]; 42 else s=sum[j+i-1]-sum[j-1]; 43 ll yueshu=j/i; 44 if(yueshu==0&&s) num[i]=0; 45 if(s)num[i]=num[i]*hh(yueshu,s)%mod; 46 } 47 } 48 for(int i=100000;i>=2;i--){ 49 dp[i]=num[i]; 50 for(int j=i+i;j<=100000;j+=i){ 51 dp[i]=(dp[i]-dp[j]+mod)%mod; 52 } 53 } 54 ll ssum=0; 55 for(int i=2;i<=100000;i++){ 56 ssum=(ssum+dp[i]+mod)%mod; 57 } 58 printf("Case #%d: %I64d\n",k++,ssum); 59 } 60 return 0; 61 }
时间: 2024-10-20 11:06:48