zoukankan      html  css  js  c++  java
  • HDU 5514 Frogs (容斥原理+因子分解)

    题目链接

    题意:有n只青蛙,m个石头(围成圆圈)。第i只青蛙每次只能条ai个石头,问最后所有青蛙跳过的石头的下标总和是多少?

    题解:暴力肯定会超时,首先分解出m的因子,自己本身不用分,因为石头编号是0到m-1,第i只青蛙只能走到gcd(ai, m)的位置,我们就可以把m的因子提取出来,然后对青蛙能走到的因子位置打标记。两个数组,第一个数组a代表是否能走到该因子,第二个数组b表示是否已经加过了,加过了几次,遍历到那个因子的时候要加上(a[i]-b[i])倍的数,这个数很可能是负数。至于公式利用等差数列前n项和可以得出。

    注意这道题是因子分解而不是素因子分解,因为对于12来说2和4是不一样的。

    注意这道题不是对数进行操作而是对因子进行操作。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b)
    {
        return b==0?a:gcd(b,a%b);
    }
    const int maxn=1e5+5;
    ll cnt=0,prime[maxn];
    void solve(ll m)
    {
        cnt=0;//注意初始化
        prime[cnt++]=1;
        for(int i=2; i<sqrt(m); i++)
        {
            if(m%i==0)
            {
                prime[cnt++]=i;
                prime[cnt++]=m/i;
            }
        }
        ll tmp=sqrt(m);
        if(tmp*tmp==m)
            prime[cnt++]=tmp;
        sort(prime,prime+cnt);
    }
    int main()
    {
        int t,cas=1;
        scanf("%d",&t);
        while(t--)
        {
            ll n,m,data,tmp;
            scanf("%lld%lld",&n,&m);
            memset(prime,0,sizeof(prime));
            solve(m);
            ll a[maxn],b[maxn];
            memset(a,0,sizeof(a));//标记
            memset(b,0,sizeof(b));//算过了几次
            for(int i=0; i<n; i++)
            {
                scanf("%lld",&data);
                tmp=gcd(data,m);
                for(int j=0; j<cnt; j++)
                {
                    if(prime[j]%tmp==0)
                        a[j]=1;
                }
            }
            ll ans=0;
            for(int i=0; i<cnt; i++)
            {
                ll num=a[i]-b[i];
                if(num!=0)
                {
                    ll tmp=(m-1)/prime[i];
                    ans=ans+tmp*(tmp+1)/2*prime[i]*num;
                    for(int j=i; j<cnt; j++)
                    {
                        if(prime[j]%prime[i]==0)
                            b[j]=b[j]+num; //注意是b表示数目
                    }
                }
            }
            printf("Case #%d: %lld
    ",cas++,ans);
        }
        return 0;
    }

     更新版:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b)
    {
        return b==0?a:gcd(b,a%b);
    }
    const int maxn=1e5+5;
    ll prime[maxn],a[maxn];
    int cnt=0;
    void solve(ll m)
    {
        memset(a,0,sizeof(a));
        memset(prime,0,sizeof(prime));
        cnt=0;
        prime[cnt++]=1;
        for(int i=2;i<sqrt(m);i++)
        {
            if(m%i==0)
            {
                prime[cnt++]=i;
                prime[cnt++]=m/i;
            }
        }
        if(ll(sqrt(m))*ll(sqrt(m))==m) prime[cnt++]=ll(sqrt(m));
        sort(prime,prime+cnt);
    }
    int main()
    {
        int t,cas=1;
        scanf("%d",&t);
        while(t--)
        {
            ll n,m,data;
            scanf("%lld%lld",&n,&m);
            solve(m);
            for(int i=0;i<n;i++)
            {
                scanf("%lld",&data);
                data=gcd(data,m);
                for(int j=0;j<cnt;j++)
                if(prime[j]%data==0) a[j]=1;
            }
            ll ans=0;
            for(int i=0;i<cnt;i++)
            {
                ll num=a[i];
                if(num!=0)
                {
                    ll tmp=(m-1)/prime[i];
                    ans+=tmp*(tmp+1)/2*prime[i]*num;
                    for(int j=i+1;j<cnt;j++)
                    if(prime[j]%prime[i]==0) a[j]-=num;
                }
            }
            printf("Case #%d: %lld
    ",cas++,ans);
        }
        return 0;
    }
  • 相关阅读:
    数值分析实验之数值积分法(java 代码)
    Python 数据处理
    Python 网络爬虫
    数据库系统开发——旅游公司机票查询及预订系统
    Python词云生成
    Python库的安装与查看
    Python词频统计
    Python程序设计训练
    Python编程基础训练
    如何在同一Linux服务器上创建多站点
  • 原文地址:https://www.cnblogs.com/Ritchie/p/5708729.html
Copyright © 2011-2022 走看看