HDU 5514 Frogs(容斥原理)

 

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

 

【题目大意】

  m个石子围成一圈,标号为0~m-1,现在有n只青蛙,每只每次跳a[i]个石子,
  问能被青蛙跳到的石子一共有几个

 

【题解】

  我们发现k*gcd(m,a[i])的位置均可以被跳到,那么我们首先筛出m的约数,
  判断其是否被覆盖到,不考虑重复的情况下,
  每个被覆盖到的约数的贡献为x*((m-1)/x)*((m-1)/x+1)/2,
  但是约数的倍数也为约数的情况被重复计算,因此我们按约数从大到小容斥计算答案。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long LL;
int T,n,m,p[20010],mark[20010],x,tot;
LL dp[20010];
int main(){
    scanf("%d",&T);
    for(int Cas=1;Cas<=T;Cas++){
        memset(dp,0,sizeof(dp));
        memset(mark,0,sizeof(mark));
        scanf("%d%d",&n,&m); tot=0;
        for(int i=1;i*i<=m;i++){
            if(m%i==0){
                p[++tot]=i;
                if(i*i!=m)p[++tot]=m/i;
            }
        }sort(p+1,p+tot+1); 
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            int GCD=__gcd(x,m);
            for(int j=1;j<=tot;j++)if(p[j]%GCD==0)mark[j]=1;
        }LL ans=0;
        for(int i=tot;i;i--)if(mark[i]){
            int t=(m-1)/p[i];
            dp[i]=1LL*t*(t+1)/2*p[i];
            for(int j=i+1;j<=tot;j++)if(mark[j]&&p[j]%p[i]==0)dp[i]-=dp[j];
            ans=ans+dp[i];
        }printf("Case #%d: %lld\n",Cas,ans);
    }return 0;
}
posted @ 2017-08-16 16:14  forever97  阅读(180)  评论(0编辑  收藏  举报