Time Limit: 1000 ms Memory Limit: 512 MB
Description
Solution
- 30%
大力(n^4)dp一波,枚举(n) ,(f[i][j][k])表示前(i)列,有(j)行有1个1,有(k)行有2个1,那么乘个组合数转移一下就好了
(这种有点鬼畜的状态表示方式类似【bzoj1079】着色方案)
- 40%
啊。。。反正。。只读一个数嘛然后(n)的范围很小单次求(n^3)跑500也不慢反正是场上那就。。。
打表啊qwq
- 70%不会qwq
- 100%
OEIS搜前四项
如果将同一行和同一列的(1)用边连起来,一种方案就可以变成。。。很多个环(好的光是这步就想不到了qwq)
那么我们考虑从这个方面入手,(f_n)表示(n*n)的矩阵的答案,那么我们枚举矩阵的第一行的(1)所在的环的大小,可以得到这样的递推式:
(注意,行与行之间、列与列之间在这题里面其实没有区别,所以可以这么考虑)
其中(A_i)表示一个(i*i)的矩阵中只有一个环的方案数,(inom n i)枚举是原矩阵的哪(i)列,(inom {n-1}{i-1})枚举是原矩阵的哪(i-1)行(因为第一行已经确定是要选的了)
然后有一个结论,(A_i=frac{n!(n-1)!}{2}),然后题解里面有这样的一个比较好的解释嗯
那么接下来就是化简式子了:
然后我们令(g_x=frac{f_x}{(x!)^2}),那么
然后我们化一下就可以得到:
好的然后会发现(g)的话直接前缀和优化一下就可以做到(O(n))了,(g)求出来之后,(f)的值也可以在线性的时间内求出,那么就可以在(O(n))的时间内解决啦
(然而。。。)
然而有个东西是(frac{1}{2n}),这个东西如果直接快速幂爆搞就会十分愉快地变成(nlogn)就会(T)了
所以我们要线性求逆元(这个东西。。晚点整理好了先贴篇blog)
最后还有一个小问题就是,(g_0)是(1),具体为什么。。(我也真的不是很知道qwq)
题外话:由于我写的太挫需要各种奇怪的常数优化才能。。卡过去qwq(然而本地没开O2真的是0.7s啊!!为什么上去就那么慢了啊qwq)什么不要用long long而是用int啊少点模啊之类的。。。%yxq巨佬10行AC
(题外话的题外话:据yxq巨佬所说这题和GDSOI2015的循环排插很像。。)
代码大概长这样
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int MAXN=1e7+10,MOD=998244353;
int fac[MAXN],invfac[MAXN];
int g[MAXN],sum[MAXN],inv[MAXN*2];
int n,m;
void prework(int n);
int ksm(int x,int y);
int sqr(int x){return 1LL*x*x%MOD;}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
ll ans=1;
int inv2=ksm(2,MOD-2);
scanf("%d",&n);
prework(n);
g[1]=0; g[2]=sqr(invfac[2])%MOD;
sum[1]=1; sum[2]=sum[1]+g[2];
for (int i=3;i<=n;++i){
g[i]=1LL*inv[i]*inv2%MOD*sum[i-2]%MOD;
sum[i]=(sum[i-1]+g[i])%MOD;
}
for (int i=3;i<=n;++i){
ans=ans+1LL*fac[i]*fac[i-1]%MOD*inv2%MOD*sum[i-2]%MOD;
if (ans>MOD) ans-=MOD;
}
printf("%d
",ans);
}
void prework(int n){
fac[0]=1;
for (int i=1;i<=n;++i) fac[i]=1LL*fac[i-1]*i%MOD;
invfac[n]=ksm(fac[n],MOD-2);
for (int i=n-1;i>=0;--i) invfac[i]=1LL*invfac[i+1]*(i+1)%MOD;
inv[1]=1;
for (int i=2;i<=n;++i)
inv[i]=1LL*(MOD-(MOD/i))*inv[MOD%i]%MOD;
}
int ksm(int x,int y){
int ret=1,base=x;
for (;y;y>>=1,base=1LL*base*base%MOD)
if (y&1) ret=1LL*ret*base%MOD;
return ret;
}