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,带进去类似的算一下和或者差就好啦。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
    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;
}

  

posted @   蒟蒻JHY  阅读(315)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示