【XX Open Cup GP of Tokyo G】Matrix Inversion

【XX Open Cup GP of Tokyo G】Matrix Inversion

Description

有一个\(n*n\)的矩阵,矩阵中\(1-n*n\)每个数恰好出现一次

给出其按行顺序排的序列的逆序对数\(X\),以及按列的\(Y\)

构造出这个矩阵

Input

一行三个数\(n,X,Y\)

Output

有解输出Yes,然后输出构造的矩阵

无解输出No

Sample Input

3 8 13

Sample Output

Yes
1 3 4 
2 7 6 
9 8 5 

Data Constraint

\(1\le n\le 300\)

Solution

考虑按行排时,有两种点对,即左上至右下和右上至坐下

设为\(W,Z\)

那么\(W+Z=X,C-Z+W=Y\)\(C\)为常数)

于是可以判定是否有解

\(W\)的最大可能值为\(Wm\)\(Z\)同理

通过归纳我们可以说明所有\(W\in[0,Wm],Z\in[0,Zm]\)的情况都是有解的

这可以通过一个更强的结论证明:

从小到大填数,对于当前没填数的格子

\((i,j)\)最小/最大,\((j,i)\)最小/最大(即双关键字排序)中

一定有一个可以使原来的条件仍满足并归纳下去(可以反证说明)

于是可以简单数据结构做到\(O(n^2\log^2n)\)

也可以精细实现做到\(O(n^2)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define Fo(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define N 310

namespace IO{
	const int sz=1<<22;
	char a[sz+5],b[sz+5],*p1=a,*p2=a,*t=b,p[105];
	inline char gc(){
		return p1==p2?(p2=(p1=a)+fread(a,1,sz,stdin),p1==p2?EOF:*p1++):*p1++;
	}
	template<class T>void read(T&x){
		x=0;char c=gc();
		for(;c<'0'||c>'9';c=gc());
		for(;c>='0'&&c<='9';c=gc())x=x*10+(c-'0');
	}
	inline void flush(){fwrite(b,1,t-b,stdout),t=b;}
	inline void pc(char x){*t++=x;if(t-b==sz)flush();}
	template<class T>void write(T x,char c=' '){
		if(x==0)pc('0');int t=0;
		for(;x;x/=10)p[++t]=x%10+'0';
		for(;t;--t)pc(p[t]);pc(c);
	}
	void write(const char *s){for(;*s;pc(*s++));}
	struct F{~F(){flush();}}f;
}
using IO::read;
using IO::write;

LL X,Y,Wm,Zm,W,Z;
int T,n,ans[N][N];
struct node{
	int x,y;
	node(int _x=0,int _y=0){x=_x;y=_y;}
}w1[N*N],w2[N*N];
struct tree{
	int s[N][N];
	int lowbit(int x){return -x&x;}
	void change(int x,int y,int v){
		for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=n;j+=lowbit(j))s[i][j]+=v;
	}
	int query(int x,int y){
		int res=0;
		for(int i=x;i;i-=lowbit(i)) for(int j=y;j;j-=lowbit(j))res+=s[i][j];
		return res;
	}
	int qur(int l1,int r1,int l2,int r2){
		return query(l2,r2)-query(l2,r1-1)-query(l1-1,r2)+query(l1-1,r1-1);
	}
}t;
vector<node>d;

bool check(int x,int y){
	LL tWm=Wm,tW=W,tZm=Zm,tZ=Z;
	int A=t.qur(1,1,x,y)-1,B=t.qur(x,y,n,n)-1;
	int C=t.qur(1,y+1,x-1,n),D=t.qur(x+1,1,n,y-1);
	tWm-=A+B;tZm-=C+D;tW-=A;tZ-=C;
	if(tW<0||tZ<0||tW>tWm||tZ>tZm)return 0;
	Wm=tWm;W=tW;Zm=tZm;Z=tZ;
	t.change(x,y,-1);
	return 1;
}

int main(){
	read(n);read(X);read(Y);
	Wm=Zm=0;
	Fo(i,1,n) Fo(j,1,n)Wm+=(n-i+1)*(n-j+1)-1,Zm+=(n-i)*(n-j);
	bool flag=1;
	if(X+Y-Zm&1)flag=0;
	W=(X+Y-Zm)/2;
	Z=X-W;
	if(W<0||Z<0||W>Wm||Z>Zm)flag=0;
	if(!flag){write("No\n");continue;}
	int tot=0;
	Fo(i,1,n) Fo(j,1,n)tot++,w1[tot]=(node){i,j},w2[tot]=(node){i,j};
	int l1=1,r1=n*n,l2=1,r2=n*n;
	memset(ans,0,sizeof(ans));
	memset(t.s,0,sizeof(t.s));
	Fo(i,1,n) Fo(j,1,n)t.change(i,j,1);
	Fo(i,1,n*n){
		while(ans[w1[l1].x][w1[l1].y])l1++;
		while(ans[w1[r1].x][w1[r1].y])r1--;
		while(ans[w2[l2].y][w2[l2].x])l2++;
		while(ans[w2[r2].y][w2[r2].x])r2--;
		if(check(w1[l1].x,w1[l1].y))ans[w1[l1].x][w1[l1].y]=i;
		else if(check(w1[r1].x,w1[r1].y))ans[w1[r1].x][w1[r1].y]=i;
		else if(check(w2[l2].y,w2[l2].x))ans[w2[l2].y][w2[l2].x]=i;
		else if(check(w2[r2].y,w2[r2].x))ans[w2[r2].y][w2[r2].x]=i;
	}
	write("Yes\n"); 
	Fo(i,1,n){
		Fo(j,1,n)write(ans[i][j]);
		write("\n");
	}
	return 0;
}
posted @ 2022-11-13 21:02  冰雾  阅读(36)  评论(0编辑  收藏  举报