SD 一轮集训 day3 染色(color)

     蜜汁打表题、、

(首先L=1和L=N的情况过于傻逼(而且是特殊情况),可以先写出来,然后剩下的L的做法在下面)

     首先你要写一个打表程序,找出{1,2,....,n} 乘若干个 循环唯一的轮换可以搞出的所有排列,然后统计一下对于每个i,总环数=i 的排列的个数 cnt[i]。

     如果你规律找的好的话,是可以发现如下结论的:

          1.当L是偶数的时候,cnt[i] = s(N,i) ,其中s(,)是第一类斯特林数。

          2.当L是奇数的时候,cnt[i] = s(N,i) or 0,cnt[i]不为0当且仅当i和N的奇偶性相同。

     模数不是998244353.。。。这可怎么算斯特林数啊???

     但我们不需要把每个斯特林数都算出来啊。。。因为 最后 cnt[i] 要乘上 k^i 加入到答案里,然后有一个第一类斯特林数的公式 : k的n次上升幂 = Σ s(n,i) * k^i。

     简单来说这个公式可以总结为: 上升幂等于第一类斯特林数点积幂。

     然后L是偶数就可以直接带进去用置换的公式算了,是奇数的话要把k' = -k,带进去类似的算一下和或者差就好啦。

/*
    x的n阶上升幂 = s(n,i) * x^i 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const int ha=1e9+7,maxn=2e6;
inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}

inline int ksm(int x,int y){
	int an=1;
	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
	return an;
}

int jc[maxn+5],ni[maxn+5],pre[maxn/2+5];
int N,K,L,ans,d[2333],phi[2333],num;

inline int C(int x,int y){ return x<y?0:jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha;}

inline void init(){
	jc[0]=1;
	for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha;
	ni[maxn]=ksm(jc[maxn],ha-2);
	for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
}

inline int getp(int x){
	int an=1;
	for(int i=2;i*(ll)i<=x;i++) if(!(x%i)){
		x/=i,an*=i-1;
		while(!(x%i)) x/=i,an*=i;
	}
	return an*(x==1?1:x-1);
}

inline void solve1(){	
	for(int i=1;i<=K;i++) pre[i]=C(N-L+i-1,i-1);
	for(int i=K;i;i--) ADD(pre[i],ha-pre[i-1]);
	
	for(int i=1;i*(ll)i<=L;i++) if(!(L%i)){
		d[++num]=i;
		if(i*i!=L) d[++num]=L/i;
	}
	for(int i=1;i<=num;i++) phi[i]=getp(L/d[i]);
	
	for(int i=1;i<=num;i++) ADD(ans,ksm(K,d[i])%ha*(ll)phi[i]%ha);
	
	ans=ans*(ll)ksm(L,ha-2)%ha;
}

inline void solve2(){
	if(!(L&1)) ans=ni[N]*(ll)jc[K+N-1]%ha*(ll)ni[K-1]%ha;
	else{
		int A=add(jc[N],N<=1)*(ll)ni[2]%ha;
		if(!(N&1)) A=add(ha-A,jc[N]);
		A=ksm(A,ha-2);
		
		int B=jc[K+N-1]*(ll)ni[K-1]%ha;
		int C=N>K?0:jc[K]*(ll)ni[K-N]%ha*(ll)((N&1)?ha-1:1)%ha;
		
		if(N&1) ans=add(B,ha-C)*(ll)ni[2]%ha*(ll)A%ha;
		else ans=add(B,C)*(ll)ni[2]%ha*(ll)A%ha; 
	}
}
 
int main(){
//	freopen("color.in","r",stdin);
//	freopen("color.out","w",stdout);
	
	scanf("%d%d%d",&N,&K,&L);
	
	init();
	
	if(N==L) solve1();
	else if(L==1) ans=ksm(K,N);
	else solve2();
	
	printf("%d\n",ans);
	
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/JYYHH/p/9169202.html