【Luogu4916】魔力环(Burnside引理,组合计数)
考虑\(Burside\)引理,设\(f(x)\)表示置换拆成循环的个数为\(x\)时的答案,那么最终的结果就是\(\displaystyle \frac{\sum_{i=1}^n f(gcd(i,n))}{n}\),化简之后就是\(\displaystyle \frac{\sum_{d|n}f(d)\varphi(\frac{n}{d})}{n}\)。
考虑如何计算不动点的数量,为了方便首先把\(n=m\)的情况直接处理掉,那么现在问题变成了,把环上的点编号,所有模\(d\)相同的点都必须是同时染或者不染色,并且不能有连续的\(k\)个被染色。因为已经处理掉了\(n=m\)的情况,所以只需要至少有一个循环没有被染色,那么问题可以等价于有\(d\)个点要染其中的\(\frac{m}{d}\) 个,不能有连续的\(k\)个都被染色的方案数。
现在把要求的东西重新拿出来定义一下,即有\(N\)个球放成一圈,要给其中\(C\)个染色,不能有连续\(K\)个都被染色,求方案数。
我们把\(C\)个要染色的球拿出来,放进剩下的\(N-C\)个球组成的环的空隙之间,使得每个空隙里的球都不能超过\(K\)个。因为要确定的是标号,所以必须断环成链,那么第\(1\)个和第\(N-C\)个之间的空隙是第一个球之前和最后一个球之后这两段本质上是连在一起的,这两段加起来不能超过\(K\)个。
那么枚举第一个球之前和最后一个球之后这两段一共放了多少个球,然后前后分配一下,所以方案数就是:\(\displaystyle \sum_{i=0}^k (i+1)Put(C-i,N-C-1,K)\),其中\(Put(C,N,K)\)表示把\(C\)个球分成\(N\)组,每组不能超过\(K\)个的方案数,这个东西可以用容斥在\(O(\frac{C}{K})\)的时间里解决,所以单次的复杂度不会超过\(O(\frac{N}{K}*K)=O(N)\)。
那么这样子总的复杂度就是\(O(n+\sigma(gcd(n,m))\)。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 1000010
#define MOD 998244353
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
bool zs[MAX];
int pri[MAX],phi[MAX],tot;
int jc[MAX<<1],inv[MAX<<1],jv[MAX<<1];
void pre(int n)
{
phi[1]=1;
for(int i=2;i<=n;++i)
{
if(!zs[i])pri[++tot]=i,phi[i]=i-1;
for(int j=1;j<=tot&&i*pri[j]<=n;++j)
{
zs[i*pri[j]]=true;
if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=2;i<=n+n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n+n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=1;i<=n+n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
}
int Choose(int n,int m){if(n<m||n<0||m<0)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int Put(int m,int n){if(m<0)return 0;return Choose(n+m-1,n-1);}
int n,m,K,p[MAX];
int Insert(int m,int n,int k)
{
int ret=0;if(m<0)return 0;
for(int i=0,d=1;i<=n;++i,d=MOD-d)
if(m>=1ll*i*(k+1))ret=(ret+1ll*Put(m-i*(k+1),n)*Choose(n,i)%MOD*d)%MOD;
else break;
return ret;
}
int Calc(int d)
{
int N=n/d,C=m/d,ret=0;
if(C<=K)return Choose(N,C);
if(K==1)return (Choose(N-C+1,C)+MOD-Choose(N-C-1,C-2))%MOD;
for(int i=0;i<=K;++i)
ret=(ret+1ll*(i+1)*Insert(C-i,N-C-1,K))%MOD;
return ret;
}
int main()
{
n=read();m=read();K=read();pre(n);
if(n==m){if(K==n)puts("1");else puts("0");return 0;}
if(!m){puts("1");return 0;}
int g=__gcd(n,m),ans=0;
for(int i=1;i*i<=g;++i)
if(g%i==0)
{
ans=(ans+1ll*Calc(i)*phi[i])%MOD;
if(i*i!=g)ans=(ans+1ll*Calc(g/i)*phi[g/i])%MOD;
}
ans=1ll*ans*fpow(n,MOD-2)%MOD;
printf("%d\n",ans);
}
【Luogu4916】魔力环(Burnside引理,组合计数)的更多相关文章
- [Luogu4916]魔力环[Burnside引理、组合计数、容斥]
题意 题目链接 分析 sπo yyb 代码 #include<bits/stdc++.h> using namespace std; typedef long long LL; #defi ...
- 【等价的穿越】Burnside引理&Pólya计数法
Problem 起源: SGU 294 He's Circle 遗憾的是,被吃了. Poj有道类似的: Mission 一个长度为n(1≤n≤24)的环由0,1,2组成,求有多少本质不同的环. 实际上 ...
- BZOJ_[HNOI2008]_Cards_(置换+Burnside引理+乘法逆元+费马小定理+快速幂)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1004 共n个卡片,染成r,b,g三种颜色,每种颜色的个数有规定.给出一些置换,可以由置换得到的 ...
- Luogu P5564 [Celeste-B]Say Goodbye (多项式、FFT、Burnside引理、组合计数)
题目链接 https://www.luogu.org/problem/P5564 题解 这题最重要的一步是读明白题. 为了方便起见下面设环长可以是\(1\), 最后统计答案时去掉即可. 实际上就相当于 ...
- BZOJ 1488 Luogu P4727 [HNOI2009]图的同构 (Burnside引理、组合计数)
题目链接 (Luogu) https://www.luogu.org/problem/P4727 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.ph ...
- 【loj6538】烷基计数 加强版 加强版 Burnside引理+多项式牛顿迭代
别问我为啥突然刷了道OI题,也别问我为啥花括号不换行了... 题目描述 求含 $n$ 个碳原子的本质不同的烷基数目模 $998244353$ 的结果.$1\le n\le 10^5$ . 题解 Bur ...
- 等价类计数:Burnside引理 & Polya定理
提示: 本文并非严谨的数学分析,有很多地方是自己瞎口胡的,仅供参考.有错误请不吝指出 :p 1. 群 1.1 群的概念 群 \((S,\circ)\) 是一个元素集合 \(S\) 和一种二元运算 $ ...
- 等价类计数(Polya定理/Burnside引理)学习笔记
参考:刘汝佳<算法竞赛入门经典训练指南> 感觉是非常远古的东西了,几乎从来没有看到过需要用这个的题,还是学一发以防翻车. 置换:排列的一一映射.置换乘法相当于函数复合.满足结合律,不满足交 ...
- LOJ #6538. 烷基计数 加强版 加强版(生成函数,burnside引理,多项式牛顿迭代)
传送门. 不妨设\(A(x)\)表示答案. 对于一个点,考虑它的三个子节点,直接卷起来是\(A(x)^3\),但是这样肯定会计重,因为我们要的是无序的子节点. 那么用burnside引理,枚举一个排列 ...
- 置换群 Burnside引理 Pólya定理(Polya)
置换群 设\(N\)表示组合方案集合.如用两种颜色染四个格子,则\(N=\{\{0,0,0,0\},\{0,0,0,1\},\{0,0,1,0\},...,\{1,1,1,1\}\}\),\(|N|= ...
随机推荐
- shell脚本--CGI获取请求数据(GET / POST)
Case 1: 获取地址栏传递的参数(即通过GET方式) CGI的环境变量中有个QUERY_STRING,可以获取地址栏传递的参数,该参数可以是手动加上的,也可以是通过表单的get方式提交的,比如下面 ...
- API接口TOKEN设计
首先需要知道API是什么? API(Application Programming Interface)即应用程序接口.你可以认为 API 是一个软件组件或是一个 Web 服务与外界进行的交互的接 ...
- C#复习笔记(4)--C#3:革新写代码的方式(用智能的编译器来防错)
用智能的编译器来防错 本章的主要内容: 自动实现的属性:编写由字段直接支持的简单属性, 不再显得臃肿不堪: 隐式类型的局部变量:根据初始值推断类型,简化局部变量的声明: 对象和集合初始化程序:用一个表 ...
- 【转帖】远程显示(操作) 服务器 GUI 程序(图形化界面) (基于 X11 Forwarding + Centos + MobaXterm)
远程显示(操作) 服务器 GUI 程序(图形化界面) (基于 X11 Forwarding + Centos + MobaXterm) https://zhuanlan.zhihu.com/p/310 ...
- [转帖]浏览器的F5和Ctrl+F5
浏览器的F5和Ctrl+F5 https://www.cnblogs.com/xiangcode/p/5369084.html 在浏览器里中,按F5键和按F5同时按住Ctrl键(简称Ctrl+F5), ...
- Baby-Step-Giant-Step 很酷的算法
Baby-Step-Giant-Step BSGS算法用于解决形如: A ^ x ≡ B ( mod C ) 的问题. 学这个算法前需要具备以下知识:快速幂取模.扩展欧几里 ...
- mysql将视图数据迁移到表中
#字段必须完全一样 INSERT into table1(所有字段) select * from data.视图
- Python OpenCV人脸识别案例
■环境 Python 3.6.0 Pycharm 2017.1.3 ■库.库的版本 OpenCV 3.4.1 (cp36) ■haarcascades下载 https://github.com/ope ...
- python易混易乱(1)
字典 基础操作 <1>keys my_dict = {"name":"zhangsan","age":18} res = my_ ...
- 关于 flask 实现数据库迁移以后 如何根据创建的模型类添加新的表?
在此之前 我们先说一下常规的flask运用第三方扩展来实现数据库的迁移的三个步骤以及每步的目的. 数据库的迁移的三个步骤:(cd 到run.py所在路径) python run.py db init ...