题意
- m块石头,n只青蛙,第i青蛙步长

- 求解所有被踩过的石头的编号(0-base)和
思路
- 观察发现,对于一只青蛙,他能踩到的石头是
&preview=true)
- 暴力会炸
- 考虑从m入手,
的结果一定是m的因子
- 枚举m的因子,标记是gcd倍数的因子,这些因子会产生贡献
- 用一个cnt记录每个因子还需要计算贡献的次数
- 从小到大计算每一个cnt不为0的因子
- 计算完一个因子的贡献后,改因子所有的倍数因子也被计算了,所以要减去次数
- 对于计算贡献,每个因子的贡献是
(等差数列求和,由于0-base开始,共有m/v[i]-1项,首项v[i],公差v[i],通项公式),再乘上自己的cnt,正值代表还没算,负值代表算多了(eg:因子有4,12,36,36就被多算了一次)
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using ll=long long;
//题干有问题,应该是至少被占领了一次
vector<int>V;
vector<int>a;
int cnt[201010];
signed main() {
int n,m;
cin >> n >> m ;
a.resize(n+10);
for(int i=1;i*i<=m;i++){
if(m%i==0){
V.push_back(i);
V.push_back(m/i);
}
}
sort(V.begin(),V.end());
for(int i=0;i<n;i++){
cin >> a[i];
int g=__gcd(a[i],m);
for(int j=0;j<V.size();j++){
if(V[j]%g==0)cnt[j]=1;
}
}
ll ans=0;
for(int i=0;i<V.size();i++){
if(cnt[i]!=0){
ans+=m*(m/V[i]-1)/2*cnt[i];
for(int j=i+1;j<V.size();j++){
if(V[j]%V[i]==0){
cnt[j]-=cnt[i];
}
}
}
}
cout << ans << endl;
return 0;
}