Hdu 6035 -TrickGCD (容斥加速)

本文提供了一道关于数组序列问题的详细解答。通过优化容斥原理的应用,采用分组策略,利用二分搜索和快速幂运算,最终实现了O(n(log_2n)^2)的时间复杂度。

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

题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6053

题目大意:
给定数组A, Ai Bi 的最大取值范围,求问有多少种不同的序列B满足任意 [l,r] 区间内,gcd值不为1

分析:
gcd值不为1,即所有数都不互质,均拥有某个质因子,但是可以发现直接容斥的复杂度是 O(105)O(105)=O(1010) ,显然复杂度超标,需要优化,经过学长指导,通过对 Ai/p 的结果进行,分组,可以用每次一次 O(log2n) 复杂的二分和一次 O(log2n) 的快速幂求得一个分组的答案,每个因子均摊大约 log2n 个分组,一共至多n个因子,所以总计复杂度为 O(n(log2n)2)

代码:

#include <bits/stdc++.h>


using namespace std;

typedef long long ll;

const int maxn = 2e5+200;
const int mod = 1e9+7;
int n;
ll ans;

bool isprime[maxn];
ll pf[maxn];
int pn[maxn];
ll arr[maxn];


void init()
{
    memset(isprime,true,sizeof(isprime));
    for (int i = 2; i <= maxn ; i ++)
    {
        if (isprime[i])
        {
            for (int j = i ; j <= maxn ; j+= i)
            {
                if(!pf[j]) pf[j] = i;
                else    pf[j] *= i;
                pn[j]++;
                if (j!=i)   isprime[j] = false;
            }
        }
    }


}

ll qp(ll a ,int n)
{
    ll res = 1;
    while (n)
    {
        if (n&1) res= res*a%mod;
        a  = a*a %mod;
        n >>= 1;
    }
    return res;
}


ll solve(int p)
{
    int i = 1;
    ll res = 1;
    while (i<=n)
    {
        int l = i,r = n+1 ,mid;
        int x = arr[i]/p;
        while (1)
        {
            if (l==r-1)
                break;

            mid = (l+r)>>1;
            if (x==arr[mid]/p)
                l = mid;
            else
                r = mid;
        }

        res = res*qp(x,l-i+1)%mod;
        i = l +1;
    }
    return res%mod;
}


int main() {
    int T,t=1;
    init();
    scanf("%d",&T);

    while (T--)
    {
        ans = 0;
        scanf("%d",&n);
        for (int i = 1 ; i <= n ; i ++)
            scanf("%lld",&arr[i]);

        sort(arr+1,arr+n+1);
        int up = arr[1];
        for (int i = 2 ; i <= up ; i ++)
        {
            if (i!=pf[i])   continue;
            ll tmp = solve(i);
            if (pn[i]&1) ans += tmp%mod;
            else    ans -= tmp%mod;
            ans %=mod;
            ans = (ans+mod)%mod;
        }
        printf("Case #%d: %lld\n",t++,ans%mod);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值