2017多校训练Contest2: 1009 TrickGCD hdu6053

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  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

考虑用总数减去gcd为1的答案

那么gcd为1的答案我们只需要容斥一下,所有因子有1的答案-所有因子有2的答案……这样

对于每个因子的加减就是莫比乌斯函数。枚举每个因子的倍数然后前缀和记录区间个数可以做到均摊nlogn的复杂度

#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
int a[100001],ss[1000001];
int mu[100001],fai[100001],prime[100001],s[100001];//mu莫比乌斯 fai欧拉 
bool check[100001]; 
int tot;
long long mod=1000000007;
inline void findfai()
{
    memset(check,false,sizeof(check));
    fai[1]=1; mu[1]=1;
    int i,j;
    for(i=2;i<=100000;i++)
    {
        if(!check[i])
        {
            tot++;
            prime[tot]=i;
            fai[i]=i-1; mu[i]=-1;
        }
        for(j=1;j<=tot;j++)
        {
            if(i*prime[j]>100000)
                break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                fai[i*prime[j]]=fai[i]*prime[j]; mu[i*prime[j]]=0;
                break;
            }
            else
                fai[i*prime[j]]=fai[i]*(prime[j]-1); mu[i*prime[j]]=-mu[i];
        }
    }
    for(i=1;i<=100000;i++)
    	s[i]=s[i-1]+mu[i];
}
int n;
inline long long power(long long x,int y)
{
	long long t=1;
	while(y!=0)
	{
		if(y%2==1)
			t=t*x%mod;
		x=x*x%mod;
		y/=2;
	}
	return t;
}
inline long long calc(int x)
{
	long long p=1;
	int i;
   	for(i=x;i<=100000;i+=x)
   	{
   		p=p*power(i/x,ss[i+x-1]-ss[i-1])%mod;
   		if(i>99999)
   		{
   			int dx=1;
   			dx=11;
   		}
   	}
	return p;
}
int main()
{
//	freopen("1009.in","r",stdin);
//	freopen("1009.out","w",stdout);
	findfai();
	int T,kk=0;
	scanf("%d",&T);
	while(T>0)
	{
		kk++;
		T--;
		scanf("%d",&n);
		int i;
		long long xt=1;
		memset(ss,0,sizeof(ss));
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			xt=(xt*a[i])%mod;
			ss[a[i]]++;
		}
		for(i=1;i<=400000;i++)
			ss[i]=ss[i-1]+ss[i];
		sort(a+1,a+1+n);
		long long ans=0;
		for(i=1;i<=a[1];i++)
		{
			ans=(ans+mu[i]*calc(i))%mod;
		//	printf("%lld\n",ans);
		//	int d=100000000;
		//	while(d--);
		}
		ans=(xt-ans+mod)%mod;
		printf("Case #%d: %lld\n",kk,ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值