【经典】容斥+排列组合——cf1342E
/* 设每行都有一个,每列上每多一个攻击对就会+1, 列上多了k个,那么只有n-k列上有棋子C(n,n-k) 问题变成将n个棋子放在n-k列上,且每列必须有一个,每行必须有且仅有一个的方案数 容斥: ans=将n个棋子随便放在某一列 pow(n-k,n) -有一个空行 pow(n-k-1,n)C(n-k,1) +有两个空行 pow(n-k-2,n)C(n-k,2) ... 最后,在n行里面选n-k行的方案数是C(n,n-k) 如果是n列里选n-k列,则方案数还要再*2 所以答案是ans*C(n,n-k)*2 */ #include<bits/stdc++.h> using namespace std; #define ll long long #define mod 998244353 #define N 200006 ll n,k,F[N],inv[N]; ll Pow(ll a,ll b){ ll res=1; while(b){ if(b%2)res=res*a%mod; b>>=1;a=a*a%mod; } return res; } void init(){ F[0]=inv[0]=1; for(int i=1;i<=n;i++){ F[i]=F[i-1]*i%mod; inv[i]=Pow(F[i],mod-2); } } ll C(ll a,ll b){ if(a<b)return 0; if(a==b || b==0)return 1; return F[a]*inv[b]%mod*inv[a-b]%mod; } ll calc(ll i){//有i个空行的情况 ll res=Pow(n-k-i,n); res=res*C(n-k,i)%mod; return res; } int main(){ cin>>n>>k; init(); if(k>=n){puts("0");return 0;} else if(k==0){ cout<<F[n]<<"\n"; }else { ll ans=Pow(n-k,n); int sign=1; for(int i=1;i<=n-k-1;i++){ sign*=-1; ans=(ans+sign*calc(i)%mod+mod)%mod; } cout<<ans*C(n,n-k)*2%mod<<'\n'; } }