题目
好难啊,不会啊;啊,\(k\leq 20\),那就直接容斥吧;
我们硬点一些控制点,之后使我们必须经过这些被硬点的点;由于我们只能往右上走,所以经过这些被钦定的点的顺序是一定的,我们只需要考虑相邻两点之间的路径数最后乘起来就好;
于是我们需要推一个\(f(n,m)\)表示从\((0,0)\)走到\((n,m)\)的路径数;
如果没有那个斜向上走直接组合数即可,有了这个斜向上走我们就枚举斜向上走了多少次,于是
\[f(n,m)=\sum_{k=0}^m\binom{m+n-2k}{m-k}\binom{m+n-k}{m+n-2k}\]
\(\binom{m+n-2k}{m-k}\)就是走到了\((k,k)\)这个位置之后我们只往右往上走,\(\binom{m+n-k}{m+n-2k}\)就是把\(k\)个斜向上走插到\(n+m-2k\)步里去;
这里的模数特别小,于是我们Lucas一下,就可以\(O(m\log_p n)\)计算\(f(n,m)\),由于\(f\)之后在两两关键点之间用到,于是直接\(O(mk^2\log_p n)\)预处理好即可;
最后我们还需要考虑从最后一个钦定点走出边界的情况,设\(g(n,m)\)表示起点为\((0,0)\),矩形右上角为\((n,m)\)走出边界的方案数;
我们规定从上走出边界的点最后都要走到\((n,m+1)\),从右走出边界的都走到\((n+1,m)\);特殊的,还有在\((n,m)\)位置斜向上走出边界的,于是\(g(n,m)=f(n+1,m)+f(n,m+1)+f(n,m)\)
代码
#include
#define re register
const int mod=59393;
struct node{int x,y;}p[25];
inline int dqm(int x){return x<0?x+mod:x;}
inline int qm(int x){return x>=mod?x-mod:x;}
int fac[mod],ifac[mod],inv[mod],ans[25][25],lst[25],fst[25],id[25],n,m,k;
inline int cmp(int a,int b){return p[a].x==p[b].x?p[a].yn?0:1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
inline int Lucas(int n,int m) {
if(m>n)return 0;if(!m)return 1;
return 1ll*Lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
inline int f(int n,int m) {
if(m<0||n<0)return 0;
if(m>n)std::swap(n,m);int ans=0;
for(re int i=0;i<=m;++i)ans=qm(ans+1ll*Lucas(m+n-i,n)*Lucas(n,n-i)%mod);
return ans;
}
inline int g(int n,int m) {return qm(qm(f(n+1,m)+f(n,m+1))+f(n,m));}
inline int calc(int state) {
int cnt=0;
for(re int i=0;i>i&1)id[++cnt]=i+1;
id[++cnt]=0;int nw=(cnt&1?1:mod-1);
std::sort(id+1,id+cnt+1,cmp);
for(re int i=1;i