HDU 5514 【2015沈阳现场赛 F】 Frogs
2015-11-06 01:59
323 查看
http://acm.hdu.edu.cn/showproblem.php?pid=5514
纪念在赛场上逝去的3个小时。。。
现在即要求:∑⋃{kai}k≤Mai
做法是:
1. 先标记所有f[ai]=1
2. 对每个f[x]=1,有f[x×factM]=1
3. 接下来计算答案:对每个f[x]=1的x,要统计出所有满足gcd(k,Mx)=1(k≤Mx)的xk(k≤Mx)的和(这样保证不会重复,即约数x对答案单独的贡献)
4. 由定理知gcd(k,N)=1的k的和为ϕ(n)×n2(因为与N互素的数能两两配对和为N,而当N为>2的偶数时,N/2不与N互素,当N=2时特判满足公式)
5. 答案即为∑f[x]=1ϕ(Mx)×Mx2
注意:
第二步从小到大枚举x,可以讲factM进一步化为priM,即M的质因子
ϕ()能由积性函数性质快速求出ϕ(factM)
纪念在赛场上逝去的3个小时。。。
题目
有N≤104 个青蛙,M≤109 个石头, 第i只青蛙一次能跳ai≤109 步,所有青蛙一开始在石头0, 可以跳任意次数, 问最后所有被跳过的石头的编号之和。题解
易知,令ai=gcd(ai,M)不会影响答案现在即要求:∑⋃{kai}k≤Mai
做法是:
1. 先标记所有f[ai]=1
2. 对每个f[x]=1,有f[x×factM]=1
3. 接下来计算答案:对每个f[x]=1的x,要统计出所有满足gcd(k,Mx)=1(k≤Mx)的xk(k≤Mx)的和(这样保证不会重复,即约数x对答案单独的贡献)
4. 由定理知gcd(k,N)=1的k的和为ϕ(n)×n2(因为与N互素的数能两两配对和为N,而当N为>2的偶数时,N/2不与N互素,当N=2时特判满足公式)
5. 答案即为∑f[x]=1ϕ(Mx)×Mx2
注意:
第二步从小到大枚举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; }