Cnoi2020 四角链の题解
前面的唐性质自己想
阅读题意可得,格子的编号为 \(1,2,3,…,n\) ,数字的集合为 \({1,2,…,n-1}\)
在合法方案中,有 \(k\) 个格子填了数,所以有 \(k\) 个数字被使用,那么一共有 \((n-1)-k\) 个数字没有用
把 \(k\) 个数和 \(k\) 个字符一一对应,每个数字 \(x\) 必须放在 \(\ge x\) 的格子上
但数字放在格子上后,格子本身没有额外的区分
换个角度看:
设 \(k\) 个被选的数字集合为 \(D\) ,每个数字 \(d\) 放在格子 \(f(d)\) 且 \(f\) 是单射到 被选中的格子集合 \(G\)
我们观察格子编号 \(\ge\) 数字的条件。
假设所有格子都可用,即为任意一个数字 \(d\) 可以选 \(d,d+1,d+2,…,n\) 中任意格子
这等价于分配问题,即为将数字 \(1,2,3,…,n-1\) 分配到 \(n-k\) 个块内
这里大神Mr_RedStone已经想到是第二类斯特林数了,可是为了向我一样的蒟蒻,我们还是一步步证明
我们增设一个数字 \(n\) 和一个格子 \(n\) ,并令虚拟数字只能放进虚拟格子
这个问题是典型的计数题目中的 \(rook polynomials\) 类的题目
根据结论,答案数为 \(S(n,k)\)
代码
#include<bits/stdc++.h>
#define Code using
#define by namespace
#define jhc std
Code by jhc;
#define int long long
int in()
{
int k=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar();
return k*f;
}
void out(int x)
{
if(x<0)putchar('-'),x=-x;
if(x<10)putchar(x+'0');
else out(x/10),putchar(x%10+'0');
}
const int N=1e6+10,mod=998244353;
int jc[N],inv[N];
void init()
{
inv[0]=inv[1]=jc[0]=1;
for(int i=2;i<N;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<N;i++)inv[i]=inv[i-1]*inv[i]%mod,jc[i]=jc[i-1]*i%mod;
}
int ksm(int a,int b)
{
int res=1;
for(;b;a=a*a%mod,b>>=1)if(b&1)res=res*a%mod;
return res;
}
int C(int n,int m){return jc[n]*inv[m]%mod*inv[n-m]%mod;}
int S(int n,int k)
{
int sum=0;
for(int i=1;i<=k;i++)
if((k-i)&1)sum=(sum+mod-C(k,i)*ksm(i,n)%mod)%mod;
else sum=(sum+C(k,i)*ksm(i,n)%mod)%mod;
return sum*inv[k]%mod;
}
signed main()
{
init();
int n=in(),k=in();
out(S(n,n-k));
return 0;
}

浙公网安备 33010602011771号