SPOJ Transposing is Even More Fun
作者:互联网
直接交换需要的次数为 $2^{a+b}$,如果有 $k$ 个循环,每个循环元素为 $x$ 个,只需要交换 $x-1$ 次,那么最后次数就是 $2^{a+b}-k$,本质就是求有多少个循环。
一个位置 $(x,y)$ 看成二进制的形式。
例如 $a=3, b=2$,位置 $(3,2)$ 看成二进制就是 $011 10$,交换后就是 $10011$,右移了 $b=2$ 位,那么就是求 $01$ 串在右移 $b$ 位同构的情况下有多少种本质不同串。
右移 $b$ 位有 $g=\gcd(a + b,b)$ 个循环,每个循环长度为 $G= \frac{a+b}{g}$,那么现在可以看成有 $G$ 元环,旋转等价,可以染成 $2^g$ 种颜色求方案数。
#include <bits/stdc++.h> namespace IO { void read() {} template<class T, class ... T2> inline void read(T &x, T2 &... oth) { x = 0; T f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar(); x *= f; read(oth...); } } const int N = 1e6 + 7, MOD = 1000003; int prime[N], prin, phi[N], bin[N]; bool vis[N]; int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; } int qp(int a, int b = MOD - 2) { int ans = 1; while (b) { if (b & 1) ans = 1LL * a * ans % MOD; a = 1LL * a * a % MOD; b >>= 1; } return ans; } void init() { phi[1] = 1; for (int i = bin[0] = 1; i < N; i++) bin[i] = 2LL * bin[i - 1] % MOD; for (int i = 2; i < N; i++) { if (!vis[i]) { prime[++prin] = i; phi[i] = i - 1; } for (int j = 1; j <= prin && i * prime[j] < N; j++) { vis[i * prime[j]] = 1; if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; } phi[i * prime[j]] = phi[i] * phi[prime[j]]; } } } void M(int &a) { if (a >= MOD) a -= MOD; if (a < 0) a += MOD; } int solve(int n, int m) { int ans = 0; for (int i = 1; i * i <= n; i++) { if (n % i) continue; M(ans += 1LL * phi[n / i] * bin[i * m] % MOD); if (i * i != n) M(ans += 1LL * phi[i] * bin[n / i * m] % MOD); } return 1LL * ans * qp(n) % MOD; } int main() { init(); int T; IO::read(T); while (T--) { int a, b; IO::read(a, b); if (!a || !b) { puts("0"); continue; } int g = gcd(a, b); int n = (a + b) / g, m = g; int ans; M(ans = bin[a + b] - solve(n, m)); printf("%d\n", ans); } }View Code
标签:Even,bin,ch,int,while,SPOJ,ans,Fun,MOD 来源: https://www.cnblogs.com/Mrzdtz220/p/12232282.html