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; } |
我爱学习,学习使我快乐
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步