CF1086E Beautiful Matrix
codeforces
一般的套路显然转化按位确定
第一行直接算有多少字典序比他小就行了。
对于\(2\)到\(n\)行,每行的总方案数就是错排数量。
这就存在一个问题,我们无法确定当前行能放的有多少字典序比它小。
我们发现对于第\(i\)行第\(j\)个,假如第\(i-1\)行前\(j\)个数和第\(i\)行前\(j\)个数一共有\(y\)个不同的数,那么在剩下的\(n-j\)个数中,就存在\(y\)个位置不受限制,也就是一共存在\(n-j-y\)个限制,那么现在的问题就是我们需要求出\(f[i][j]\)表示\(i\)个数,存在\(j\)个限制的排列数。
容易得出\(f[i][j]=f[i][j-1]-f[i-1][j-1]\),\(n\)个数\(n\)个限制就是错排。
现在需要考虑的问题是我们需要算出每个位置能放的比\(a[i][j]\)小的数有多少。
这又有两种情况:
我们发现对于第\(i\)行第\(j\)个,假如第\(i-1\)行前\(j\)个一共有\(x\)个比\(a[i][j]\)小的数字在第\(i\)行前\(j-1\)个中没有出现过。
1、那么这个位置放这\(x\)个数就会导致前\(j\)个数一共只剩下\(x-1\)个数不同,也就是后\(n-j\)个数有\(n-j-x+1\)个限制
2、假如不放这\(x\)个数,依然是\(x\)个限制
细节貌似不多,反正我是写自闭了
代码:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define rg register
void read(int &x){
char ch;bool ok;
for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
}
const int maxn=2010,mod=998244353;bool vis[maxn],used[maxn];
int n,a[maxn][maxn],f[maxn][maxn],fac[maxn],ans;
int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y){return x-y<0?x-y+mod:x-y;}
int g[2][maxn],ff[maxn];
#define lowbit(i) (i&(-i))
void ins(int a,int x,int z){for(rg int i=x;i<=n;i+=lowbit(i))g[a][i]+=z;}
int get(int a,int x){int ans=0;for(rg int i=x;i;i-=lowbit(i))ans=add(ans,g[a][i]);return ans;}
int main(){
read(n);fac[0]=1;
for(rg int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
for(rg int i=1;i<=n;i++)
for(rg int j=1;j<=n;j++)
read(a[i][j]);
f[0][0]=1;
for(rg int i=1;i<=n;i++){
f[i][0]=fac[i];
for(rg int j=1;j<=i;j++)
f[i][j]=del(f[i][j-1],f[i-1][j-1]);
}
ff[0]=1;
for(rg int i=1;i<=n;i++)ff[i]=mul(ff[i-1],f[n][n]);
for(rg int j=1;j<=n;j++){
int t=0;
for(rg int i=1;i<a[1][j];i++)if(!vis[i])t++;
ans=add(ans,mul(mul(t,fac[n-j]),ff[n-1]));
vis[a[1][j]]=1;
}
memset(vis,0,sizeof vis);
for(rg int i=2;i<=n;i++){
for(rg int j=1;j<=n;j++){
int t=a[i][j]-1-get(0,a[i][j]-1),h=get(1,a[i][j]-1);
if(!vis[a[i-1][j]]&&a[i-1][j]<a[i][j])t--;
if(!vis[a[i-1][j]])ins(1,a[i-1][j],1);vis[a[i][j]]=1;
ans=add(ans,mul(add(mul(f[n-j][n-j-get(1,n)+1],h),mul(f[n-j][n-j-get(1,n)],t-h)),ff[n-i]));
ins(0,a[i][j],1);
if(used[a[i][j]])ins(1,a[i][j],-1);used[a[i-1][j]]=1;
}
for(rg int j=1;j<=n;j++)g[0][j]=g[1][j]=vis[j]=used[j]=0;
}
printf("%d\n",ans);
}