http://acm.hdu.edu.cn/showproblem.php?pid=5514
纪念在赛场上逝去的3个小时。。。
题目
有
N≤104
个青蛙,
M≤109
个石头, 第
i
只青蛙一次能跳
题解
易知,令
现在即要求:
∑⋃{kai}k≤Mai
做法是:
1. 先标记所有
f[ai]=1
2. 对每个
f[x]=1
,有
f[x×factM]=1
3. 接下来计算答案:对每个
f[x]=1
的
x
,要统计出所有满足
4. 由定理知
5. 答案即为
注意:
第二步从小到大枚举 x ,可以讲factM 进一步化为 priM ,即 M 的质因子
ϕ() 能由积性函数性质快速求出 ϕ(factM)
code
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
typedef long long LL;
const int maxn = 10010;
int n, m;
int a[maxn];
int pri[20], pri_N;
void get_pri(int n) {
for (int p = 2; p*p <= n && n > 1; ++ p) {
if (n%p == 0) {
pri[pri_N ++] = p;
while (n%p == 0) n /= p;
}
}
if (n > 1) pri[pri_N ++] = n;
}
int phi(int n) {
int res = n;
for (int p = 2; p*p <= n && n > 1; ++ p) {
if (n%p == 0) {
res = res / p * (p-1);
while (n%p == 0) n /= p;
}
}
if (n > 1) res = res / n * (n-1);
return res;
}
LL res;
std::set<int> f;
typedef std::set<int>::iterator IT;
int gcd(int a, int b) { while (b) { int c = a; a = b; b = c%b; } return a; }
void solve() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++ i) { scanf("%d", &a[i]); a[i] = gcd(a[i], m); }
pri_N = 0;
get_pri(m);
res = 0; f.clear();
for (int i = 0; i < n; ++ i) f.insert(a[i]);
for (IT it = f.begin(); it != f.end(); ++ it) {
for (int i = 0; i < pri_N; ++ i) if (m % ((LL)*it * pri[i]) == 0)
f.insert((LL)*it * pri[i]);
LL s = (LL)m / *it * phi(m / *it) / 2;
res += s * *it;
}
printf("%I64d\n", res);
}
int main() {
// freopen("F.in", "r", stdin);
int kase, i = 0; scanf("%d", &kase);
while (kase --) {
printf("Case #%d: ", ++ i);
solve();
}
// for(;;);
return 0;
}