HDU 2239 polya计数 欧拉函数
这题模数是9937还不是素数,求逆元还得手动求。
项链翻转一样的算一种相当于就是一种类型的置换,那么在n长度内,对于每个i其循环节数为(i,n),但是由于n<=2^32,肯定不能直接枚举,所有考虑枚举gcd,对应的n/gcd就是其个数,有点容斥的思想。全部累加最后除以n就计算好染色方案了。
注意这题很卡时间,而且很玄的用long long会错,要先求出上界再枚举,循环中i*i的循环条件会很慢。
/** @Date : 2017-09-18 23:33:30 * @FileName: HDU 2239 EXGCD 求逆元.cpp * @Platform: Windows * @Author : Lweleth (SoungEarlf@gmail.com) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h> #define LL __int64 #define PII pair #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1e5 + 10; const double eps = 1e-8; const LL mod = 9937; int pri[N]; int c = 0; bool vis[N]; void prime() { MMF(vis); for(int i = 2; i < N; i++) { if(!vis[i]) pri[c++] = i; for(int j = 0; j < c && i * pri[j] < N; j++) { vis[i *pri[j]] = 1; if(i % pri[j] == 0) break; } } } LL get_phi(int x) { LL res = x; int ma = sqrt(x + 0.5); for(int i = 0; i < c && pri[i] <= ma; i++) { if(x % pri[i] == 0) { while(x % pri[i] == 0) x /= pri[i]; res = res / pri[i] * (pri[i] - 1); } } if(x > 1) res = res / x * (x - 1); return res % mod; } LL exgcd(LL a, LL b, LL x, LL y) { LL d = a; if(b == 0) x = 1, y = 0; else { d = exgcd(b, a % b, y, x); y -= (a / b) * x; } return d; } LL fpow(LL a, LL n) { LL res = 1; while(n) { if(n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res; } int main() { LL n, m; prime(); while(~scanf("%I64d%I64d", &n, &m)) { LL ans = 0; int ma = sqrt(n + 0.5); for(int i = 1; i <= ma; i++) { if(n % i != 0) continue; ans = (ans + get_phi(n / i) * fpow(m, i) % mod + mod) % mod; if(i != n / i) ans = (ans + get_phi(i) * fpow(m, n / i) % mod + mod) % mod; } for(LL i = 0; i < mod; i++) if(i * n % mod == ans % mod) { ans = i; break; } /*cout << ans << endl; ans = ans * mod % (n * mod) / n;*/ printf("%I64d\n", ans); } return 0; }