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; }
我爱学习,学习使我快乐