HDU-5514 Frogs
Posted dsjkafdsaf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU-5514 Frogs相关的知识,希望对你有一定的参考价值。
题目描述
有\(n\)只青蛙,\(m\)个围成圆圈的石头。第\(i\)只青蛙每次只能跳\(a_i\)个石头,问最后所有青蛙跳过的石头的下标总和是多少?
Input
第一行为\(T\) 表示数据组数
每一组数据第一行为\(n\)和\(m\)
第二行有\(n\)个整数 表示每只青蛙一步跳的距离
\(T<=20,1<=n<=10^4,1<=m<=10^9,1<=a_i<=10^9\)
Output
对于每组数据 输出"Case #x: "(不含引号)以及答案
Sample Input
3
2 12
9 10
3 60
22 33 66
9 96
81 40 48 32 64 16 96 42 72
Sample Output
Case #1: 42
Case #2: 1170
Case #3: 1872
很容易就可以想到,每只青蛙可以跳到的石头的编号一定是\(gcd(m,a_i)\)的倍数。
那么问题就变成了,给出\(n\)个数\(B_i\),问小于等于\(m\)中为\(B_i\)倍数的数的和为多少。
对于一只青蛙,其能够跳到的石头的编号是一个等差数列。
这个,我们可以利用高斯求和解决,答案就是\(((m-1)/B[i]*B[i]*((m-1)/B[i]+1))/2\)
然而,我们发现,如果把答案加上所有的青蛙的答案,其中会有很多重复的被算了好几次。
我们需要利用容斥去求解。
我们发现,会造成重复的编号一定是满足两只青蛙具有倍数关系的青蛙,并且由于是\(gcd\)所以一定是\(m\)的因子。
所以我们应该从\(m\)的因子上来考虑。
于是,我们先将\(m\)的所有因子给求出来。
然后,对于每个青蛙的步长\(A_i\)并求出\(B_i\),枚举\(m\)的因子,若该因子是青蛙\(B_i\)的倍数。
则给该因子打一个标记,由于该因子已经被计算过了一次。
所以,其倍数造成的贡献已经被它给计算过了一次,所以要减去他造成的贡献。
但由于,我们无法直接计算一个数多造成的贡献,但可以快速的计算出一个数被因子计算了几次。
既然多算了那么多次,减掉就好了。。。。
于是我们就有了这样的伪算法:
for(i:对于m的因子)
if(该因子已经被计算的次数!=应该被计算的次数)
int temp=该因子已经被计算的次数-应该被计算的次数;
Ans+=temp*贡献。
for(j:对于m的因子)if(j是当前因子i的倍数)
//说明被多计算了。
j已经被计算的次数+=temp;
前面我们已经说过了一个数的贡献,直接计算即可。
代码如下
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
#define int long long
#define reg register
#define Raed Read
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
inline int Read(void)
int res=0,f=1;
char c;
while(c=getchar(),c<48||c>57)if(c=='-')f=0;
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>=48&&c<=57);
return f?res:-res;
template<class T>inline bool Min(T &a, T const&b)
return a>b?a=b,1:0;
template<class T>inline bool Max(T &a, T const&b)
return a<b?a=b,1:0;
const int N=1e4+5,M=1e5+5,mod=110119;
bool MOP1;
int A[N],B[N],vis[N],Num[N];
int gcd(int x,int y)
return !y?x:gcd(y,x%y);
bool MOP2;
inline void _main(void)
int T=Read(),Case=0;
while(T--)
int n=Read(),m=Read(),tot=0,Ans=0;
clr(vis,0),clr(Num,0);
for(reg int i=1; i*i<=m; i++)if(!(m%i))
B[++tot]=i;
if(i*i!=m)B[++tot]=m/i;
sort(B+1,B+tot+1),tot--;
rep(i,1,n)
A[i]=Read(),A[i]=gcd(A[i],m);
rep(j,1,tot)if(!(B[j]%A[i]))vis[j]=1;
rep(i,1,tot)
if(vis[i]==Num[i])continue;
int Now=(m-1)/B[i],temp=vis[i]-Num[i];
Ans+=(Now*B[i]*(Now+1))*temp/2;
rep(j,1,tot)if(!(B[j]%B[i]))Num[j]+=temp;
printf("Case #%lld: %lld\n",++Case,Ans);
signed main()
_main();
return 0;
以上是关于HDU-5514 Frogs的主要内容,如果未能解决你的问题,请参考以下文章