2017第二次多校联合hdu6053Tirck Gcd

本文探讨了一类关于确定序列B的问题,其中B的序列需满足特定的数学约束条件,特别是任意子集的GCD(最大公约数)至少为2。通过分析,提出了有效的算法解决方案,包括使用容斥原理和莫比乌斯函数来去除重复计数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假装这里有链接

题意:给出A的序列,然后根据A的序列去确定B的序列。
B的序列满足1BiAi且对于任意B的子集的gcd2.

解:首先考虑任意B的子集的gcd2这个条件。它代表的含义即B中任意两个数不互质。那个B中的数都是倍数关系。然后再来看A,已知了A序列,那我们可以枚举小于A但是大于1的所有数。拿样例来看,A的序列为4 4 4 4,然后从2开始枚举,枚举到2的时候,2是4的因子,且44,所以这时候不论是取2还是取4都是可以的,所以是4*C(12),然后枚举到3,只有这一种情况,然后到4,也是一种情况,但是在枚举2的时候已经考虑的2的倍数4的情况了,所以重复去掉,答案是16+4=17.
经过简单的推导,我们可以推出含重复答案的公式为:aminx=2(ni=1a[i]x)
下面我们开始讨论重复的答案如何去重。应用简单的容斥原理,就是下面的那张图,然后用筛法求莫比乌斯函数实现。
|A∪B∪C|=|A|+|B|+|C|−|A∩B|−|B∩C|−|A∩C|+|A∩B∩C|
这里写图片描述

但是从对每个可能的Bi都枚举一遍A,这样是n2的时间复杂度对于105的数据来说是绝对会超时的,所以需要优化。
仔细观察可以得知,在某个范围里的数对于一个固定的Bi所对应的种数是一样的。比如对于5来说,1-4里面有0个5,5-9里面有5个5,10-14里面有2个5……………..
所以我们就可以将这一个整块的数据同时处理,这样就会节约很多时间。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
#define ll long long
ll m[100010];
void mu()
{
    m[1]=1;
    for(ll i=1; i<=maxn; i++)
        for(ll j=2*i; j<=maxn; j+=i)
        {
            m[j]-=m[i];
        }
}
ll a[maxn],num[2*maxn];
ll qmod(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()
{
    ll minx,t,ca=1;
    mu();
    scanf("%lld",&t);
    while(t--)
    {
        memset(a,0,sizeof a);
        memset(num,0,sizeof num);
        ll n;
        scanf("%lld",&n);
        minx=maxn+10;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            minx=min(a[i],minx);
        }
        for(int i=1; i<=n; i++)
        {
            num[a[i]]++;
        }
        for(int i=1; i<=200000; i++)
        {
            num[i]+=num[i-1];
        }
        ll ans=0;
        for(ll i=2; i<=minx; i++)
        {
            ll sum=1;
            for(ll j=1; j*i<=100000; j++)
            {
                sum=(sum*qmod(j,num[(j+1)*i-1]-num[j*i-1]))%mod;
                //j代表优化中拿的种数
            }
            ans=(ans-sum*m[i]%mod+mod)%mod;
        }
        printf("Case #%lld: %lld\n",ca++,ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值