hdu 4633 Who's Aunt Zhang
polya计数,费马小定理
分为以下几种循环节:
初始态;对面旋转;对点旋转;对棱旋转
幸好题目规模不大,肉眼完全可以数出来
#include<cstdio> #include<algorithm> #include<vector> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int mod = 10007; int k; int mpower(int b, int a) { int res = 1, p = b; while (a) { if (a & 1) res = res*p%mod; p = p*p%mod; a >>= 1; } return res; } int cal() { int res = 0; res += mpower(k, 54+8+12); res += mpower(k, 3+3+9+3+2)*3; res += mpower(k, 5+5+18+6+4)*3; res += mpower(k, 3+3+9+3+2)*3; res += mpower(k, 27+7+4)*6; res += mpower(k, 18+4+4)*4; res += mpower(k, 18+4+4)*4; res %= mod; return res*mpower(24, mod-2)%mod; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int t, cs = 1; scanf("%d", &t); while (t--) { printf("Case %d: ", cs++); scanf("%d", &k); printf("%d\n", cal()); } return 0; }
即便是借鉴了别人的思路,还是费了不少力气。新学到了利用欧拉函数优化环形polya计数的方法若数据庞大,分解质因子后搜索可大幅提升效率#include<cstdio> #include<algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef __int64 ll; const ll mod = 1000000007; const int MAXN = 32000; bool isPrime[MAXN] = {false}; ll prime[MAXN], res, color, all, ssm; int np = 0; void init() { for (int i = 2; i< MAXN; ++i) { if (!isPrime[i]) prime[np++] = i; for (int j = 0; j<np && prime[j]*i< MAXN; ++j) { isPrime[prime[j]*i] = true; if (i % prime[j] == 0) break; } } } ll mpower(ll b, ll a) { ll res = 1, p = b%mod; // 失误点:b可能大于mod while (a) { if (a & 1) res = res*p%mod; p = p*p%mod; a >>= 1; } return res; } ll getTran(ll a, ll c) { const ll ny = mpower(4, mod-2); if (a & 1) { return (mpower(c, a*a) + mpower(c, (a*a+3)>>2)*2%mod + mpower(c, (a*a+1)>>1))*ny%mod; } else { return (mpower(c, a*a) + mpower(c, (a*a)>>2)*2%mod + mpower(c, (a*a)>>1))*ny%mod; } } ll fact[100], fenjie[100][2]; int nfac, nfen; void addFac(ll aa) // 失误点:本例中素数未全部列出 { for (int i = 0; i< np && prime[i]*prime[i] <= aa; ++i) { while ( aa % prime[i] == 0) aa /= prime[i], fact[nfac++] = prime[i]; } if (aa != 1) fact[nfac++] = aa; } void dfs2(int idx, ll x, ll sa, ll sb, ll a, ll c) { if (idx == nfen) { ll k = a / x; ssm = (ssm + mpower(c, k)*(x/sa*sb%mod)%mod)%mod; } else { ll cn = 0, p = fenjie[idx][1], q = fenjie[idx][0]; for ( ; cn <= p; ++cn) { if (cn == 0) dfs2(idx+1, x, sa, sb, a, c); else dfs2(idx+1, x, sa*q, sb*(q-1), a, c); x *= q; } } } void dfs(int idx, ll b) { if (idx == nfen) { ll ncol = getTran(b, color); ll k = (all*all-1)/b/b; ssm = 0; dfs2(0, 1, 1, 1, k, ncol); ssm = ssm*mpower(k, mod-2)%mod; res = (res + ssm)%mod; } else { ll cn = 0, s = fenjie[idx][1]; for ( ; cn <= s; ) { fenjie[idx][1] -= cn; dfs(idx+1, b); fenjie[idx][1] += cn; cn += 2; b *= fenjie[idx][0]; } } } ll solve() { res = 0; nfac = 0; nfen = 0; addFac(all-1); addFac(all+1); sort(fact, fact + nfac); fenjie[0][0] = fact[0]; fenjie[0][1] = 1; for (int i = 1; i< nfac; ++i) { if (fact[i] == fact[i-1]) { fenjie[nfen][1]++; } else { nfen++; fenjie[nfen][0] = fact[i]; fenjie[nfen][1] = 1; } } nfen++; dfs(0, 1); return res*color%mod; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int t, cs = 0; init(); scanf("%d", &t); while (t--) { printf("Case %d: ", ++cs); scanf("%I64d%I64d", &all, &color); if (all == 1) printf("%I64d\n", color); else printf("%I64d\n", solve()); } return 0; }
Java的大数用着就是爽import java.math.BigInteger; import java.util.Scanner; public class Main { static Scanner cin = new Scanner(System.in); public static void main(String[] args) { final BigInteger mod = BigInteger.valueOf(10).pow(15); int t = 0, cs = 1; t = cin.nextInt(); while ((t--) != 0) { System.out.print("Case "+(cs++)+": "); BigInteger c = cin.nextBigInteger(), p; BigInteger sum = BigInteger.valueOf(0), cnt = BigInteger.valueOf(24); p = c.pow(8); sum = sum.add(p); p = c.pow(2).multiply(BigInteger.valueOf(6)); sum = sum.add(p); p = c.pow(4).multiply(BigInteger.valueOf(17)); sum = sum.add(p); sum = sum.divide(cnt); if (sum.compareTo(mod) > 0) { sum = sum.mod(mod); String msString = sum.toString(); for (int i = msString.length(); i < 15; ++i) System.out.print(0); } System.out.println(sum); } } }
polya及其优化,组合数学对于每种置换,不变的着色方案数的计算 可转化为 环着色,根据题意为n个节点的环着m种颜色且相邻节点颜色不同的方案数为:(m-1)^a + (-1)^n * ((m-1)^3 - m*(m-1)*(m-2))需要注意的是若n == 1,则方案数为0(题目的特殊性质决定)#include<cstdio> #include<algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef __int64 ll; const ll mod = 1000000007; const int MAXN = 32000; bool isPrime[MAXN] = {false}; ll prime[MAXN], np = 0; ll nn, mm; void initPrime() { for (int i = 2; i< MAXN; ++i) { if(!isPrime[i]) prime[np++] = i; for (int j = 0; j<np && i*prime[j]<MAXN; ++j) { isPrime[i*prime[j]] = true; if (i % prime[j] == 0) break; } } } ll npow(ll a, ll b) { ll res = 1, p = a%mod; while (b) { if (b & 1) res = res*p%mod; p = p*p % mod; b >>= 1; } return res; } ll fenzi[100][2]; int nfen; void divide(ll a) { for (int i = 0; i< np && prime[i]*prime[i] <= a; ++i) { if (a % prime[i] == 0) { fenzi[nfen][0] = prime[i]; fenzi[nfen][1] = 0; while (a % prime[i] == 0) { a /= prime[i]; fenzi[nfen][1]++; } nfen++; } } if (a != 1) { fenzi[nfen][0] = a; fenzi[nfen++][1] = 1; } } ll resAll; ll getCircle(ll m, ll n) { ll res; if (n == 1) return 0; if (n == 2) return m*(m-1)%mod; res = (npow(m-1, 3) - m*(m-1)%mod*(m-2)%mod)%mod; res = n&1?-res:res; res = (res + mod)%mod; res = (res + npow(m-1, n)) % mod; return res; } void dfs(int i, ll p1, ll p2, ll x) { if (i == nfen) { ll t = nn/x; resAll = (resAll + getCircle(mm-1, t)*(x/p1*p2%mod)%mod)%mod; }else { int cnt = 0, p = fenzi[i][1], q = fenzi[i][0]; for ( ;cnt <= p; ++cnt) { if (!cnt) dfs(i+1, p1, p2, x); else dfs(i+1, p1*q, p2*(q-1), x); x *= q; } } } ll solve() { nfen = 0; resAll = 0; divide(nn); dfs(0, 1, 1, 1); return resAll*npow(nn, mod-2)%mod*mm%mod; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif initPrime(); while (scanf("%I64d%I64d", &nn, &mm) != EOF) { printf("%I64d\n", solve()); } return 0; }
hdu 5080 Colorful Toy
核心是找出置换群,所以先找中心,再根据置换的步数暴力搜索#include <stdio.h> #include <vector> #include <string> #include <algorithm> #include <queue> #include <cstring> #include <map> #include <set> #include <iostream> #include <cmath> using namespace std; typedef long long LL; const int MAXN = 55; const LL MOD = 1e9+7; const double eps = 1e-8, PI = acos(-1.0); inline int zero(double a) { return (a>eps) - (a<-eps); } struct _Point { double x, y; double angle, dis; _Point (double x=0.0, double y=0.0) {this->x=x; this->y=y;} bool operator == (const _Point & a) const { return !zero(x-a.x) && !zero(y-a.y); } void getDis() { dis = sqrt(x*x + y*y); } _Point rota(double ag) { return _Point(dis*cos(angle+ag), dis*sin(angle+ag)); } } pt[MAXN], center; bool mmp[MAXN][MAXN]; int n, m, c; int P[MAXN], cnt, Permt[MAXN], np; bool cmp(const int a, const int b) { if (zero(pt[a].angle - pt[b].angle) != 0) return pt[a].angle < pt[b].angle; return (pt[a].dis) < (pt[b].dis); } int check_pt() { double rs = pt[Permt[P[0]]].angle - pt[P[0]].angle; for (int i = 0; i< cnt; ++i) { if (!(pt[Permt[P[i]]] == pt[P[i]].rota(rs))) return 0; } return 1; } int check_link() { for (int i = 0; i< n; ++i) { for (int j = 0; j< n; ++j) if (mmp[i][j] != mmp[Permt[i]][Permt[j]]) return 0; } return 1; } bool vis[MAXN]; LL mpow(LL a, LL b) { LL res = 1, p = a; while (b) { if (b & 1) res = res*p%MOD; p = p*p%MOD; b >>= 1; } return res; } LL solve() { int ans = 0; memset(vis, 0, sizeof vis); for (int i = 0; i<n; ++i) { if (!vis[i]) { ++ans; for (int tp=i; !vis[tp]; tp = Permt[tp]) vis[tp] = 1; } } return mpow(c, ans); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int t, u, v; scanf("%d", &t); while (t--) { scanf("%d%d%d", &n, &m, &c); center.x = center.y = 0.0; for (int i = 0; i< n; ++i) scanf("%lf%lf", &pt[i].x, &pt[i].y), center.x += pt[i].x, center.y += pt[i].y; center.x /= n; center.y /= n; cnt = 0; for (int i = 0; i< n; ++i) { pt[i].x -= center.x; pt[i].y -= center.y; pt[i].getDis(); if (pt[i] == center) { Permt[i] = i; continue; } pt[i].angle = atan2(pt[i].y, pt[i].x); P[cnt++] = i; } sort(P, P+cnt, cmp); memset(mmp, 0, sizeof mmp); for (int i = 0; i< m; ++i) { scanf("%d%d", &u, &v); --u; --v; mmp[u][v] = mmp[v][u] = 1; } LL res = 0LL; np = 0; for (int i = 0; i< cnt; ++i) // 转过i个单位 { for (int j = 0; j< cnt; ++j) Permt[P[j]] = P[(i+j)%cnt]; if (check_pt() && check_link()) { ++np; res = res + solve(); } } cout<<res*mpow(np,MOD-2)%MOD <<endl; } return 0; }