【LuoguP4916】魔力环
题意
求出 \(n\) 个珠子的在旋转同构意义下的手 环 个数,满足以下条件:
恰好有 \(m\) 个黑色珠子,其余为白色。
黑色珠子形成的最长连续段不能超过 \(k\) 个。
Sol
考虑 \(Burnside\) 引理\(/Polya\) 定理 , 那么答案就是:
\]
\(f(i)\) 表示在转 \(i\) 次的置换下所有合法染色方案中能够产生不动点的个数。这样我们就不用考虑旋转同构的问题了。
对于转 \(i\) 次的一个置换 , 显然它把这个长度为 n 的链分成了 \(gcd(n,i)\) 个环(也就是循环) , 那么一种方案要是不动点的话就必须满足这些环中的所有元素都是同色。
我们设 \(d=gcd(n,i)\) , 把式子再次变形:
\]
这是个常见的式子了, \(n\) 中与 \(i\) 的 \(gcd\) 是 \(d\) 的数有 \(\varphi(\frac{n}{d})\) 个。
那么:
\]
\(F(d)\)表示现在有 \(\frac{n}{d}\) 个循环 , 模\(d\)意义下在同一个剩余系中的珠子颜色要相同且黑色珠子不能有连续的超过 \(k\) 个 , 求合法的染色方案数。
因为当 \(d\) 确定下来的话 , 被分成的循环的情况也就确定了 , 模 \(d\) 相同的在一个环里。
既然这样 , 首先我们直接特判 \(n=m\) 的情况 , 这样由于染色的决策是一个循环的过程 , 每\(d\)个珠子之间就可以看作是互不影响了 , 于是就相当于我们现在有 \(d\) 个珠子 , 要给其中 \(\frac{m}{\frac{n}{d}}=\frac{md}{n}\) 个染成黑色 , 黑色段最长不能超过 \(k\) 个的合法方案数了。
由于是一个环直接做不好考虑首尾 , 所以直接枚举首尾总共已经有 \(i\) 个球被染色 , 那么我们就希望求出 \(Paint(n,m,k)\) 表示有 \(n\) 个球排成一列 , 首尾已经都是白色的 , 现在要给中间的球染成黑色,满足黑色段最长不超过 \(k\) 的方案数。
由于球是等价的 , 这样我们可以把原问题变成 现在有 \(n-m\) 个球 , 要在其中的 \(n-m-1\) 个空隙里插入 \(m\) 个球 , 要求每个空隙里不能插入超过 \(k\) 个球 , 求方案数。
这是一个简单的容斥问题了 , 我们枚举至少有多少个空隙插入了多余 \(k\) 个球 , 剩下的就隔板法求一个方案数就行了。这里复杂度只有 \(O(\frac{m}{k})\)
然后我们由于要枚举环首尾有多少个黑珠子 , 所以单次计算一个 \(F\) 的复杂度是 \(O(m)\) 的
但是注意这里的 \(m\) 不是原来的 \(m\) 它是 \(\frac{md}{n}\)
如果我们用 \(d'\) 来替换 \(\frac{n}{d}\) , 这样复杂度就是 \(O(\sum_{d'|n}\frac{m}{d'})\)
\(d'\) 还必须是 m的约数 , 所以显然我们的复杂度是 \(gcd(n,m)\) 的约数和 ,可以轻松通过。
#include<bits/stdc++.h>
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e6+10;
const int mod=998244353;
template <typename T> inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
typedef long long ll;
template <typename T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
template <typename T>inline void Dec(T&x,int y){x-=y;if(x < 0) x+=mod;return;}
template <typename T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) ret=(ll)ret*x%mod;return ret;}
int Sum(int x,int y){x+=y;if(x>=mod) return x-mod;return x;}
int Dif(int x,int y){x-=y;if(x < 0 ) return x+mod;return x;}
int n,m,k;
int gcd(int a,int b){return b? gcd(b,a%b):a;}
int pri[N],vis[N],cnt=0,phi[N],fac[N],finv[N];
inline int C(int n,int m){return n<m? 0:((ll)fac[n]*finv[m]%mod*finv[n-m]%mod);}
inline void Sieve(){
phi[1]=1;vis[1]=1;fac[0]=finv[0]=fac[1]=finv[1]=1;
int n=1e6;
for(int i=2;i<=n;++i) {
if(!vis[i]) pri[++cnt]=i,phi[i]=i-1;
fac[i]=(ll)fac[i-1]*i%mod;
for(int j=1;j<=cnt;++j){
int nt=i*pri[j];if(nt>n) break;
vis[nt]=1;
if(i%pri[j]==0) {phi[nt]=phi[i]*pri[j];break;}
phi[nt]=phi[i]*phi[pri[j]];
}
}
finv[n]=fpow(fac[n],mod-2);
for(int i=n-1;i;--i) finv[i]=(ll)finv[i+1]*(i+1)%mod;
return;
}
inline int Solve(int n,int m,int k){
if(!m) return 1;
++k;int mx=m/k;int ans=0;
for(int i=0;i<=mx;++i) {
int ret=m-i*k;
int res=(ll)C(n,i)*C(n+ret-1,n-1)%mod;
if(i&1) Dec(ans,res);else Inc(ans,res);
}
return ans;
}
inline int Calc(int n,int m){
int ret=0;int ed=min(m,k);
for(int i=0;i<=ed;++i) Inc(ret,(ll)(i+1)*Solve(n-m-1,m-i,k)%mod);
return ret;
}
int main()
{
Sieve();init(n),init(m),init(k);
if(n==m) {puts((k>=n)? "1":"0");return 0;}
int ans=0;
for(int i=1;i*i<=n;++i) {
if(n%i==0) {
if((m*i%n)==0) Inc(ans,(ll)Calc(i,m*i/n)*phi[n/i]%mod);
if(n/i!=i&&m%i==0) Inc(ans,(ll)Calc(n/i,m/i)*phi[i]%mod);
}
}
ans=(ll)ans*fpow(n,mod-2)%mod;
printf("%d\n",ans);
return 0;
}
【LuoguP4916】魔力环的更多相关文章
- Luogu4916 魔力环 莫比乌斯反演、组合、生成函数
传送门 先不考虑循环同构的限制,那么对于一个满足条件的序列,如果它的循环节长度为\(d\),那么与它同构的环在答案中就会贡献\(d\)次. 所以如果设\(f_i\)表示循环节长度恰好为\(i\)的满足 ...
- [Luogu4916]魔力环[Burnside引理、组合计数、容斥]
题意 题目链接 分析 sπo yyb 代码 #include<bits/stdc++.h> using namespace std; typedef long long LL; #defi ...
- 【Luogu4916】魔力环(Burnside引理,组合计数)
考虑\(Burside\)引理,设\(f(x)\)表示置换拆成循环的个数为\(x\)时的答案,那么最终的结果就是\(\displaystyle \frac{\sum_{i=1}^n f(gcd(i,n ...
- luogu P4916 魔力环
传送门 表示这种\(Burnside\)定理之类的东西一用就忘qwq 题目要求不同染色方案数,因为变换方式只有旋转,所以只有\(n\)个置换,然后可能会出现某种方案有循环节,这个循环节长度显然要是\( ...
- LOJ6519. 魔力环(莫比乌斯反演+生成函数)
题目链接 https://loj.ac/problem/6519 题解 这里给出的解法基于莫比乌斯反演.可以用群论计数的相关方法代替莫比乌斯反演,但两种方法的核心部分是一样的. 环计数的常见套路就是将 ...
- [jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)
题目链接: https://jzoj.net/senior/#main/show/6084 https://www.luogu.org/problemnew/show/P4916 题目: 题解: 注: ...
- loj6519 魔力环
解题思路 考虑顺时针旋转 \(i\) 步得到的结果,根据Burnside引理,有 \[ Ans=\frac{\sum\limits_{i=0}^{n-1}C(i)}{n} \] \(C(i)\) 为旋 ...
- 「MtOI2018」魔力环
首先发现是经典的循环置换本质不同个数模型,根据 Burnside 引理: \[|X / G| = \frac{1}{|G|}\sum\limits_{g \in G} |X ^ g| \] 考虑第 \ ...
- GOOD BYE OI
大米饼正式退役了,OI给我带来很多东西 我会的数学知识基本都在下面了 博客园的评论区问题如果我看到了应该是会尽力回答的... 这也是我作为一个OIer最后一次讲课的讲稿 20190731 多项式乘法 ...
随机推荐
- 《ECMAScript6 入门》
NVM Babel babel-core:提供 Babel 的 API,可以获得转码后的代码和抽象语法树. babel-polyfill:Babel 只能转换语法,如果想用类似 Promise.Gen ...
- fiddler之简单的接口性能测试(replay)
在针对某一个/某一些接口,发送相同的请求,不考虑参数的变化时,可以使用fiddler进行简单的性能测试.(使用功能为:replay) 一.replay功能调用 (1.Reissue Requests: ...
- eclipse code recommenders cannot download its model repository index
Cent OS 7 运行 eclipse oxygen 代码提示出现标题所示的错误,解决办法,将网络提供程序设置为手动即可解决. Window->Preference->General-& ...
- 【Fiddler】开启手机的http或https抓包
fiddler安装 下载fiddler最新版: 默认安装: 打开fiddler工具,默认界面: 选择上方,Tools-→options General界面 HTTPS界面 CONNECTIONS,po ...
- python2和python3中split的坑
执行同样的split,python2和python3截取的行数内容却不一样 我想要截取Dalvik Heap行,使用split('\n')的方法 import os cpu='adb shell du ...
- python3--udp/TCP笔记和实践
UDP协议: UDP (User Datagram Protocol, 用户数据报协议) 是一种无连接,不可靠,基于数据的传输层通信协议. UDP的通信过程与TCP相比比较为简单, 不需要复杂的三次握 ...
- 避免浏览器缓存JS
有时候更改了JS代码,但是浏览器内容不变,这样<script src="Scripts/myjs/Master.js?v"></script>引入JS就可以 ...
- 解决172.17 或者172.18 机房环境下harbor服务器不通的问题
直接改docker-compose.yml文件: 把原来的network选项注释掉,自定义 #networks: # harbor: # external: false networks: harbo ...
- linux文件属性软链接
linux里的软链接 相当于windows系统中的快捷方式 软链接总结: 1.删除源文件,软链接文件依然存在,但是无法访问指向源文件路径内容. 2.失效时候一般是白字红底闪烁显示. test -> ...
- 创建React脚手架
node版本10.14.2 下载地址 如果是其版本的话会出错 css-loader 会不兼容 主要是8.x的版本不兼容 npm install -g create-react-app 全局安装 cre ...