Description
Irena和Sirup正准备下个周末的Party。为这个Party,他们刚刚买了一个非常大的圆桌。他们想邀请每个人,但他们现在不知道如何分配座次。Irena说当有超过K个女孩座位相邻(即这些女孩的座位是连续的,中间没有男孩)的话,她们就会说一整晚的话而不和其他人聊天。
Sirup没有其他选择,只有同意她。然而,作为一名数学家,他很快地痴迷于所有可能方案。
题目说明:
N个人围绕着圆桌坐着,其中一些是男孩,另一些是女孩。你的任务是找出所有合法的方案数,使得不超过K个女孩座位是连续的。
循环同构会被认为是同一种方案。
Input
第一行有一个数T,表示以下有T组数据,每组数据有两个整数N,K。
每组数据之间有一个空行隔开。
Output
输出T行,每行顺次对应一组测试数据。
每组数据你需要输出最后的方案数除以100000007的余数。
Sample Input
3
3 1
3 3
4 1
Sample Output
2
4
3
解释:
第一组数据的方案是:MMM,MMW (M是男孩, W是女孩)。
第二组数据的方案是:MMM,MMW,MWW,WWW。
第三组数据的方案是:MMMM, MMMW,MWMW。
Data Constraint
对于20%的数据T<=20;
对于100%的数据T<=50;
对于20%的数据N,K<=20;
对于100%的数据N,K<=2000;
题解
这题我们利用Burnside引理来做。
不会的戳这里:https://blog.csdn.net/HiChocolate/article/details/91830427
首先我们观察burnside的公式,对于某个置换所得到的循环节长度我们可以知道是
并且,这些循环节是可以通过旋转得到其他循环节的。
所以说,我们只需要确定内的不定点个数即可套burnside
如果n<=k的时候,可以直接套burnside,不定点个数即为
如果n>k的时候,就有点麻烦。
我们发现,只需要讨论这以内的方案。
所以考虑DP。我们设表示当前长度为,首尾都是男生时并且内部女生数量不过k的方案数。
很好转移,直接枚举倒数第二个男生的位置,累加入f即可。
初始化
现在我们可以愉快转移了。
首先1~n地去枚举i,得到一个循环节长度。
然后枚举j的长度,因为我们要使得女生个数不过k,所以j从开始,得到贡献即为
至于为什么,我们可以发现,f只确定了长度,没有确定位置,所以我们可以同样地去旋转它。
每次旋转在整个循环节旋转i次都是一个全新的不定点。
最后套上burnside即可
标程
uses math;
var
i,j,k,l,n,m,t:longint;
g,f:array[-1..2000] of int64;
mo:int64=100000007;
ans:int64;
function gcd(a,b:longint):longint;
begin
if b=0 then exit(a);
exit(gcd(b,a mod b));
end;
function qsm(a,b:int64):int64;
var
t,y:int64;
begin
t:=1;y:=a;
while b>0 do
begin
if b mod 2=1 then t:=t*y mod mo;
y:=y*y mod mo;
b:=b div 2;
end;
exit(t);
end;
begin
readln(t);
while t>0 do
begin
dec(t);
readln(n,k);
if n<=k then
begin
ans:=0;
for i:=1 to n do
begin
ans:=(ans+qsm(2,gcd(n,i))) mod mo;
end;
ans:=ans*qsm(n,mo-2) mod mo;
writeln(ans);
continue;
end;
fillchar(f,sizeof(f),0);
f[1]:=1;f[2]:=1;
for i:=3 to n do
begin
for j:=max(1,i-k-1) to i-1 do
begin
f[i]:=(f[i]+f[j]) mod mo;
end;
end;
ans:=0;
for i:=1 to n do
begin
for j:=max(gcd(n,i)-k,1) to gcd(n,i) do
begin
ans:=(ans+f[j]*(gcd(n,i)-j+1)) mod mo;
end;
end;
ans:=ans*qsm(n,mo-2) mod mo;
writeln(ans);
end;
end.
end.