【题目链接】 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 ",Cas,ans); }return 0; }