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);
}

posted @ 2019-09-20 13:30  蒟蒻--lichenxi  阅读(224)  评论(0编辑  收藏  举报