3134. 魔法手链

题目链接

3134. 魔法手链

给定 m 种不同颜色的魔法珠子,每种颜色的珠子的个数都足够多。

现在要从中挑选 n 个珠子,串成一个环形魔法手链。

魔法珠子之间存在 k 对排斥关系,互相排斥的两种颜色的珠子不能相邻,否则会发生爆炸。(同一种颜色的珠子之间也可能存在排斥

请问一共可以制作出多少种不同的手链。

注意,如果两个手链经旋转后能够完全重合在一起,对应位置的珠子颜色完全相同,则视为同一种手链。

答案对 9973 取模。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含三个整数 n,m,k

接下来 k 行,每行包含两个整数 a,b,表示颜色 a 的珠子不能和颜色 b 的珠子相邻。

m 种颜色编号为 1m

输出格式

每组数据输出一行一个整数,表示答案。

数据范围

1T10,
1n109,
gcd(n,9973)=1,
1m10,
0km(m+1)2,
1a,bm

输入样例:

4 3 2 0 3 2 1 1 2 3 2 2 1 1 1 2 3 2 3 1 1 1 2 2 2

输出样例:

4 2 1 0

解题思路

burnside

本题即 3133. 串珠子 的加强版,由于多了循环置换之间的限制,所以不能用 polya 定理,只能用 burnside 引理

本题只考虑旋转,每次旋转 k 次,旋转的次数为 n/gcd(k,n),共 gcd(k,n) 个可能相交的循环置换,则每次置换时只用考虑长度为 gcd(k,n) 这段形成环的方案数,先考虑对于非环的情况,dp 求解,f[i][j] 表示前 i 个点最后一个点为 j 时的方案数,这部分答案为前一个合法状态的总和,但 n 过大,考虑矩阵优化,设 F[i]=f[i][j],可以发现:F[i+1]=F[i]×A,其中 A 为限制矩阵,则有 Fn=F1×An,故可用矩阵乘法优化 dp,另外这里不需要考虑环的情况,因为矩阵乘法已经满足首尾限制了,还有一点,由于 n 过大,不可能枚举所有的 k,但是可以找出有多少个这样的 gcd(k,n),设 d=gcd(k,n),则这样的 dϕ(n/d)

int 范围内的最多约数个数为 1600,故:

  • 时间复杂度:O(T×1600×(m3×logn+n)

代码

// Problem: 魔法手链 // Contest: AcWing // URL: https://www.acwing.com/problem/content/3137/ // Memory Limit: 64 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=15,mod=9973; int t,n,m,k; struct matrix { int a[N][N]; matrix() { memset(a,0,sizeof a); } }; matrix operator*(matrix a,matrix b) { matrix c; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) for(int k=1;k<=m;k++) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } int phi(int n) { int res=n; for(int i=2;i<=n/i;i++) if(n%i==0) { res=res/i*(i-1); while(n%i==0)n/=i; } if(n>1)res=res/n*(n-1); return res%mod; } int ksm(matrix a,int n) { matrix res; for(int i=1;i<=m;i++)res.a[i][i]=1; while(n) { if(n&1)res=res*a; a=a*a; n>>=1; } int ret=0; for(int i=1;i<=m;i++)ret=(ret+res.a[i][i])%mod; return ret; } int qmi(int a,int b,int p) { int res=1%p; while(b) { if(b&1)res=1ll*res*a%p; a=1ll*a*a%p; b>>=1; } return res; } int main() { for(scanf("%d",&t);t;t--) { scanf("%d%d%d",&n,&m,&k); matrix ma; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++)ma.a[i][j]=1; for(int i=1;i<=k;i++) { int a,b; scanf("%d%d",&a,&b); ma.a[a][b]=ma.a[b][a]=0; } int res=0; for(int i=1;i<=n/i;i++) if(n%i==0) { res=(res+1ll*ksm(ma,i)*phi(n/i)%mod)%mod; if(i!=n/i) res=(res+1ll*ksm(ma,n/i)*phi(i)%mod)%mod; } printf("%d\n",res*qmi(n,mod-2,mod)%mod); } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16800906.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(141)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示