【POJ2888】Magic Bracelet
\(\text{Solution}\)
考虑眼切,你就\(AC\)了
对于求本质不同的方案数,显然可以用\(Burnside\)引理。
接着\(DP\)求方案数,对于头尾的限制,可以在最后在加一个和头部一样的珠子。用矩阵优化即可。
\(\text{Code}\)
#include<cstdio>
#include<cstring>
using namespace std;
const int P = 9973,N = 1e6 + 5;
int n,ans,m,T,k,vis[N],p[N],tot,cnt;
struct nd{int s[10][10];}a,O,I,b;
struct nid{int z,s;}c[N];
void init()
{
for (int i = 0; i < 10; i++) I.s[i][i] = 1;
for (int i = 2; i <= 1000000; i++) {
if (!vis[i]) p[++tot] = i;
for (int j = 1; j <= tot && p[j] * i <= 1000000; j++)
{
vis[p[j] * i] = 1;
if (i % p[j] == 0) break;
}
}
}
nd Mul(nd x,nd y)
{
nd z = O;
for (int k = 0; k < m; k++)
for (int i = 0; i < m; i++) if (x.s[i][k])
for (int j = 0; j < m; j++)
z.s[i][j] = (z.s[i][j] + x.s[i][k] * y.s[k][j] % P) % P;
return z;
}
int fpow(int x,long long y)
{
long long res = 1;
for (; x; x >>= 1,y = y * y % P)
if (x & 1) res = res * y % P;
return res;
}
void dfs(int x,int sum,int phi)
{
if (x > cnt)
{
b = I; int id = sum; nd y = a;
for (; id; id >>= 1,y = Mul(y,y))
if (id & 1) b = Mul(b,y);
long long res = 0;
for (int i = 0; i < m; i++) res = (res + b.s[i][i]) % P;
res = (long long)res * phi % P;
ans = (ans + res) % P;
return;
}
int g = 1;
for (int i = 0; i < c[x].s; i++) dfs(x + 1,sum * g,phi / g),g = g * c[x].z;
dfs(x + 1,sum * g,phi / (g / c[x].z) / (c[x].z - 1));
}
int main()
{
init(),scanf("%d",&T);
for (; T; T--)
{
scanf("%d%d%d",&n,&m,&k),ans = 0,cnt = 0;
int g = n; memset(c,0,sizeof c);
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++) a.s[i][j] = 1;
for (int i = 1; i <= tot && p[i] <= g; i++)
{
if (g % p[i] == 0) c[++cnt].z = p[i];
while (g % p[i] == 0) c[cnt].s++,g /= p[i];
}
if (g != 1) c[++cnt] = nid{g,1};
for (int i = 1,q,p; i <= k; i++)
scanf("%d%d",&q,&p),q--,p--,a.s[q][p] = a.s[p][q] = 0;
int Phi = n;
for (int i = 1; i <= cnt; i++) Phi = Phi / c[i].z * (c[i].z - 1);
dfs(1,1,Phi),ans = ans * fpow(P - 2,n) % P;
printf("%d\n",ans);
}
}

浙公网安备 33010602011771号