hdu5514Frogs(容斥,好题)

本文针对一个特定的数学问题——青蛙跳跃问题进行了深入分析。通过使用最大公约数(GCD)和容斥原理,提出了一种有效的算法来计算在特定范围内哪些位置可以被青蛙达到。文章详细解释了算法的设计思路及实现过程。

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

题意:

有一个0-m-1的环,有n只青蛙从0这个点开始跳,问哪些点可以被跳到

分析:

经分析我们可以知道,一个点如果可以被跳到,那么他一定为gcd(x,m)的倍数,如果直接把这些点相加,显然,某些点可能被加了2次甚至更多
很容易想到容斥,但是怎么容斥又是一个难点

假设num[i]是能够被跳到的点,那么num[i]的倍速一定能够跳到,这会形成一个等差数列,.利用求和公式便可知道,

但是到了num[i]*2的时候,这个数列的后面几项又会被重新算一遍,所以只需要vis[j]-vis[i],意思便是多退少补,如果前面减得多了,那么vis[j]便会是正数,

反之为负数

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
int vis[maxn],num[maxn],cnt;

int gcd(int x,int y){
    if(x<y)
        swap(x,y);
    if(y==0)
        return x;
    return gcd(y,x%y);
}

void init(int m){
    memset(vis,0,sizeof(vis));
    cnt=0;
    num[cnt++]=1;
    for(int i=2;i*i<=m;i++){
        if(m%i==0){
            if(i*i==m)
                num[cnt++]=i;
            else{
                num[cnt++]=i;
                num[cnt++]=m/i;
            }
        }
    }
}

int main(){
    int _,n,m,x;
    scanf("%d",&_);
    for(int case1=1;case1<=_;case1++){
        scanf("%d%d",&n,&m);
        init(m);
        sort(num,num+cnt);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            x=gcd(x,m);
            for(int j=0;j<cnt;j++){
                if(num[j]%x==0)
                    vis[j]=1;
            }
        }
        __int64 ans=0;
        for(int i=0;i<cnt;i++){
            if(vis[i]!=0){
                __int64 tmp=m/num[i];
                ans+=(tmp-1)*tmp/2*num[i]*vis[i];
                for(int j=i+1;j<cnt;j++)
                    if(num[j]%num[i]==0)
                        vis[j]-=vis[i];
            }
        }
        printf("Case #%d: %I64d\n",case1,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值