Codechef September Challenge 2018 游记

Codechef September Challenge 2018 游记

Magician versus Chef

题目大意:

有一排\(n(n\le10^5)\)个格子,一开始硬币在第\(x\)个格子里。\(m(m\le10^4)\)次操作,每次交换指定的两个格子。问最后硬币在第几个格子里。

思路:

按题意模拟即可。

源代码:

#include<cstdio>
#include<cctype>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
int main() {
	for(register int T=getint();T;T--) {
		const int n=getint();
		int x=getint();
		for(register int s=getint();s;s--) {
			const int a=getint(),b=getint();
			if(a==x) {
				x=b;
			} else if(b==x) {
				x=a;
			}
		}
		printf("%d\n",x);
	}
	return 0;
}

Chef and Adventures

题目大意:

你有两个属性\(a\)\(b\),一开始\(a=b=1\)。你可以进行以下两种操作:

  1. \(a\)\(b\)\(+1\),该操作至多进行一次;
  2. \(a+=x\)\(b+=y\)

问最后能否使\(a=n\)\(b=m\)

思路:

枚举是否进行第一种操作,然后直接取模判断是否可行即可。

源代码:

#include<cstdio>
#include<cctype>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
int main() {
	for(register int T=getint();T;T--) {
		const int n=getint()-1,m=getint()-1,x=getint(),y=getint();
		if(n%x==0&&m%y==0) {
			puts("Chefirnemo");
			continue;
		}
		if(n&&m&&(n-1)%x==0&&(m-1)%y==0) {
			puts("Chefirnemo");
			continue;
		}
		puts("Pofik");
	}
	return 0;
}

War of XORs

题目大意:

给你一个数列\(A_{1\sim n}(n\le10^5,A_i\le10^6)\),求满足\(1\le i<j\le n\)的数对\((i,j)\)的个数,使得\(A_i\oplus A_j\)可以写成两个奇偶性相同的质数的和。

思路:

根据哥德巴赫猜想,题目想问的就是异或起来的结果是偶数(不包括\(0\)\(2\))的数对个数。

源代码:

#include<cstdio>
#include<cctype>
#include<cstring>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
typedef long long int64;
const int A=1<<20;
int cnt[2],set[A];
int64 tmp[2];
int main() {
	for(register int T=getint();T;T--) {
		memset(set,0,sizeof set);
		cnt[0]=cnt[1]=tmp[0]=tmp[1]=0;
		const int n=getint();
		for(register int i=0;i<n;i++) {
			const int x=getint();
			tmp[0]+=set[x];
			tmp[1]+=set[x^2];
			set[x]++;
			cnt[x&1]++;
		}
		printf("%lld\n",(int64)cnt[0]*(cnt[0]-1)/2+(int64)cnt[1]*(cnt[1]-1)/2-tmp[0]-tmp[1]);
	}
	return 0;
}

Bad Shuffle

题目大意:

按如下方式生成一个长度为\(n(n\le17)\)的排列:

P := [1, 2, ..., N]
for i in 1..N do
    j := rand(1, N)
    swap(P[i], P[j])

\(p(P)\)表示排列\(P\)被生成的概率,求\(p(P)\)最小的\(P\)\(p(P)\)最大的\(P\)。如有多种,输出任意一种即可。

思路:

找规律。

源代码:

#include<cstdio>
#include<cctype>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
int main() {
	const int n=getint();
	for(register int i=2;i<=n/2;i++) printf("%d ",i);
	printf("%d ",1);
	for(register int i=n/2+2;i<=n;i++) printf("%d ",i);
	printf("%d\n",n/2+1);
	for(register int i=1;i<=n;i++) {
		printf("%d%c",(i-2+n)%n+1," \n"[i==n]);
	}
	return 0;
}

Table Game

题目大意:

Alice和Bob在玩桌游:有一张\((n+1)\times(m+1)(n,m\le10^5)\)的桌子,在上面进行游戏。记第\(i\)行第\(j\)列的格子为\((i,j)(0\le i\le n,0\le j\le m)\),游戏规则如下:

  • 初始时,桌上某个格子中有一块石头。
  • 双方轮流操作,Alice执先手。
  • 每回合中,当前玩家需要将石头从其当前格子(记为\((x,y)\))移动到\((x−1,y)\)\((x,y−1)\)
  • 当石头被移动到的位置\((x,y)\)满足\(x=0\)\(y=0\)时,游戏结束。
  • 胜者由进行最后一回合的玩家以及游戏结束时石头所处的格子共同决定,这一信息在输入中给出。请注意,石头一定不会到达 \((0,0)\)
    你需要回答\(q(q\le10^5)\)个询问,每个询问给定石头的初始位置\((x,y)\),你需要求出游戏的胜者。

思路:

观察发现只需要求出前两行/列是必胜态还是必败态,其余可以通过前面的状态算出来。

源代码:

#include<cstdio>
#include<cctype>
#include<cstring>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
const int N=1e5+1;
bool b[3][N],c[N][3];
char s[N];
int main() {
	for(register int T=getint();T;T--) {
		scanf("%s",s);
		const int m=strlen(s);
		for(register int i=0;i<m;i++) {
			b[0][i+1]=s[i]^'0';
			if(i+1<=2) c[0][i+1]=s[i]^'0';
		}
		scanf("%s",s);
		const int n=strlen(s);
		for(register int i=0;i<n;i++) {
			c[i+1][0]=s[i]^'0';
			if(i+1<=2) b[i+1][0]=s[i]^'0';
		}
		for(register int i=1;i<=2;i++) {
			for(register int j=1;j<=m;j++) {
				b[i][j]=!b[i][j-1]||!b[i-1][j];
			}
		}
		for(register int j=1;j<=2;j++) {
			for(register int i=1;i<=n;i++) {
				c[i][j]=!c[i][j-1]||!c[i-1][j];
			}
		}
		const int q=getint();
		for(register int i=0;i<q;i++) {
			const int x=getint(),y=getint();
			if(x<=2) {
				printf("%d",b[x][y]);
				continue;
			}
			if(y<=2) {
				printf("%d",c[x][y]);
				continue;
			}
			if(x<y) {
				printf("%d",b[2][y-(x-2)]);
			} else {
				printf("%d",c[x-(y-2)][2]);
			}
		}
		puts("");
	}
	return 0;
}

Sasha and Photos

题目大意:

两个尺寸\(h_1\cdot w_1\)\(h_2\cdot w_2(h_1w_1,h_2w_2\le10^6)\)的黑白照片,你将它放大成两个\(\operatorname{lcm}(h_1,h_2)\cdot\operatorname{lcm}(w_1,w_2)\)的照片,问两张照片有多少对应位置颜色相等。

思路:

枚举一张照片上原有的格子,求出在新照片上对应另一张照片的哪些格子。使用前缀和统计即可。

源代码:

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
#define int long long
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
inline bool getbit() {
	register char ch;
	while(!isdigit(ch=getchar()));
	return ch^'0';
}
const int N=1e6;
std::vector<int> a[N],b[N];
inline int sum(const int &x,const int &y,const bool &t) {
	int ret=b[x][y];
	if(x!=0) ret-=b[x-1][y];
	if(y!=0) ret-=b[x][y-1];
	if(x!=0&&y!=0) ret+=b[x-1][y-1];
	if(t==0) ret=1-ret;
	return ret;
}
inline int sum(const int &x0,const int &y0,const int &x1,const int &y1,const bool &t) {
	if(x0>x1||y0>y1) return 0;
	int ret=b[x1][y1];
	if(x0!=0) ret-=b[x0-1][y1];
	if(y0!=0) ret-=b[x1][y0-1];
	if(x0!=0&&y0!=0) ret+=b[x0-1][y0-1];
	if(t==0) ret=(x1-x0+1)*(y1-y0+1)-ret;
	return ret;
}
int area(const int &x,const int &y) {
	return std::max(x,0ll)*std::max(y,0ll);
}
signed main() {
	for(register int T=getint();T;T--) {
		const int h1=getint(),w1=getint();
		for(register int i=0;i<h1;i++) {
			a[i].resize(w1);
			for(register int j=0;j<w1;j++) {
				a[i][j]=getbit();
			}
		}
		const int h2=getint(),w2=getint();
		for(register int i=0;i<h2;i++) {
			b[i].resize(w2);
			for(register int j=0;j<w2;j++) {
				b[i][j]=getbit();
				if(i!=0) b[i][j]+=b[i-1][j];
				if(j!=0) b[i][j]+=b[i][j-1];
				if(i!=0&&j!=0) b[i][j]-=b[i-1][j-1];
			}
		}
		const int h0=std::__gcd(h1,h2),w0=std::__gcd(w1,w2);
		int ans=0;
		for(register int i=0;i<h1;i++) {
			const int a1=i*h2/h0,b1=(i+1)*h2/h0-1;
			for(register int j=0;j<w1;j++) {
				const int c1=j*w2/w0,d1=(j+1)*w2/w0-1;
				const bool &t=a[i][j];
				const int u=a1/(h1/h0),d=b1/(h1/h0);
				const int l=c1/(w1/w0),r=d1/(w1/w0);
				ans+=sum(u,l,t)*area(std::min((u+1)*h1/h0-1,b1)-a1+1,std::min((l+1)*w1/w0-1,d1)-c1+1);
				if(l!=r) ans+=sum(u,r,t)*area(std::min((u+1)*h1/h0-1,b1)-a1+1,d1-std::max(r*w1/w0,c1)+1);
				if(u!=d) ans+=sum(d,l,t)*area(b1-std::max(d*h1/h0,a1)+1,std::min((l+1)*w1/w0-1,d1)-c1+1);
				if(u!=d&&l!=r) ans+=sum(d,r,t)*area(b1-std::max(d*h1/h0,a1)+1,d1-std::max(r*w1/w0,c1)+1);
				ans+=sum(u,l+1,u,r-1,t)*area(std::min((u+1)*h1/h0-1,b1)-a1+1,w1/w0);
				if(u!=d) ans+=sum(d,l+1,d,r-1,t)*area(b1-std::max(d*h1/h0,a1)+1,w1/w0);
				ans+=sum(u+1,l,d-1,l,t)*area(h1/h0,std::min((l+1)*w1/w0-1,d1)-c1+1);
				if(l!=r) ans+=sum(u+1,r,d-1,r,t)*area(h1/h0,d1-std::max(r*w1/w0,c1)+1);
				ans+=sum(u+1,l+1,d-1,r-1,t)*area(h1/h0,w1/w0);
			}
		}
		printf("%lld\n",ans);
		for(register int i=0;i<h1;i++) a[i].clear();
		for(register int i=0;i<h2;i++) b[i].clear();
	}
	return 0;
}

AND Square Subsegments

题目大意:

给你一个长度为\(n(n\le10^5)\)的数列\(A(A_i<2^30)\)\(q(q\le5\times10^5)\)次询问,每次询问\(A_{[l,r]}\)中有多少子序列满足所有数按位与的结果是完全平方数。

思路:

将询问离线,按右端点排序。考虑加入一个数作为右端点。对于一个右端点\(A_r\),向左不断按位与后,一旦某一位变成\(0\)就再也不能变回\(1\)了。因此根据按位与的结果最多可以分成\(30\)段。

看一下这一段对应的结果是否是完全平方数,如果是就将对应的区间\(+1\)。线段树维护即可。

源代码:

#include<cmath>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
#include<functional>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
using int64=long long;
const int N=1e5+1,B=30,M=5e5;
struct Query {
	int l,r,id;
	bool operator < (const Query &rhs) const {
		return r<rhs.r;
	}
};
Query q[M];
int a[N],pos[B];
int64 ans[M];
std::vector<std::pair<int,int>> tmp;
inline bool check(const int &x) {
	return floor(sqrt(x))*floor(sqrt(x))==x;
}
class SegmentTree {
	#define _left <<1
	#define _right <<1|1
	#define mid ((b+e)>>1)
	private:
		int tag[N<<2];
		int64 val[N<<2];
		int len(const int &b,const int &e) const {
			return e-b+1;
		}
		void push_down(const int &p,const int &b,const int &e) {
			if(tag[p]==0) return;
			tag[p _left]+=tag[p];
			tag[p _right]+=tag[p];
			val[p _left]+=tag[p]*len(b,mid);
			val[p _right]+=tag[p]*len(mid+1,e);
			tag[p]=0;
		}
		void push_up(const int &p) {
			val[p]=val[p _left]+val[p _right];
		}
	public:
		void build(const int &p,const int &b,const int &e) {
			val[p]=tag[p]=0;
			if(b==e) return;
			build(p _left,b,mid);
			build(p _right,mid+1,e);
		}
		void modify(const int &p,const int &b,const int &e,const int &l,const int &r) {
			if(b==l&&e==r) {
				tag[p]++;
				val[p]+=len(b,e);
				return;
			}
			push_down(p,b,e);
			if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r));
			if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r);
			push_up(p);
		}
		int64 query(const int &p,const int &b,const int &e,const int &l,const int &r) {
			if(b==l&&e==r) return val[p];
			push_down(p,b,e);
			int64 ret=0;
			if(l<=mid) ret+=query(p _left,b,mid,l,std::min(mid,r));
			if(r>mid) ret+=query(p _right,mid+1,e,std::max(mid+1,l),r);
			return ret;
		}
	#undef _left
	#undef _right
	#undef mid
};
SegmentTree t;
int main() {
	for(register int T=getint();T;T--) {
		memset(pos,0,sizeof pos);
		const int n=getint(),m=getint();
		t.build(1,1,n);
		for(register int i=1;i<=n;i++) {
			a[i]=getint();
		}
		for(register int i=0;i<m;i++) {
			q[i].l=getint();
			q[i].r=getint();
			q[i].id=i;
		}
		std::sort(&q[0],&q[m]);
		for(register int i=1,j=0;i<=n&&j<m;i++) {
			tmp.clear();
			for(register int j=0;j<B;j++) {
				if((a[i]>>j)%2==0) {
					pos[j]=i;
				} else {
					tmp.push_back(std::make_pair(pos[j],j));
				}
			}
			std::sort(tmp.begin(),tmp.end(),std::greater<std::pair<int,int>>());
			int last=i;
			for(register unsigned j=0;j<tmp.size();j++) {
				if(check(a[i])&&tmp[j].first!=last) {
					t.modify(1,1,n,tmp[j].first+1,last);
				}
				a[i]^=1<<tmp[j].second;
				last=tmp[j].first;
			}
			if(check(a[i])&&last!=0) {
				t.modify(1,1,n,1,last);
			}
			for(;j<m&&q[j].r==i;j++) {
				ans[q[j].id]=t.query(1,1,n,q[j].l,q[j].r);
			}
		}
		for(register int i=0;i<m;i++) {
			printf("%lld\n",ans[i]);
		}
	}
	return 0;
}

Chef and Condition Zero (Challenge)

题目大意:

给你一个\(n\times m(n,m\le1000)\)的网格,每个格子都有一个权值\(w_{i,j}\),请你尝试构造一种方案,将该网格图分成四连通的\(k(k\le1000)\)块,使得权值和最大的块的权值与权值和最小的块的权值之差尽量小。

思路:

普通贪心。将所有权值之和\(\div k\)作为参照。每次分块尽量接近这个数,并将差值加入下一次分块中。用各种顺序跑一边去个最小值。

按照考场上最后的评分参数得到\(197.67829\)分。

源代码:

#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
typedef long long int64;
const int N=1001;
int n,m,k,a[N][N],sid;
long double ans=1e18;
int64 avg,del,tot;
namespace sol01 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int i=1;i<=n;i++) {
			if(i&1) {
				for(register int j=1;j<=m;j++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int j=m;j>=1;j--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=1;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol02 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int i=1;i<=n;i++) {
			if(!(i&1)) {
				for(register int j=1;j<=m;j++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int j=m;j>=1;j--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=2;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol03 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int j=1;j<=m;j++) {
			if(!(j&1)) {
				for(register int i=1;i<=n;i++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int i=n;i>=1;i--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=3;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol04 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int j=1;j<=m;j++) {
			if(j&1) {
				for(register int i=1;i<=n;i++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int i=n;i>=1;i--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=4;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol05 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int i=n;i>=1;i--) {
			if(i&1) {
				for(register int j=1;j<=m;j++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int j=m;j>=1;j--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=5;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol06 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int i=n;i>=1;i--) {
			if(!(i&1)) {
				for(register int j=1;j<=m;j++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int j=m;j>=1;j--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=6;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol07 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int j=m;j>=1;j--) {
			if(!(j&1)) {
				for(register int i=1;i<=n;i++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int i=n;i>=1;i--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=7;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
namespace sol08 {
	int b[N][N];
	int64 sum[N];
	void main() {
		del=0;
		int cnt=1;
		for(register int j=m;j>=1;j--) {
			if(j&1) {
				for(register int i=1;i<=n;i++) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			} else {
				for(register int i=n;i>=1;i--) {
					if(cnt<k&&sum[cnt]+a[i][j]>avg+del) {
						del=avg+del-sum[cnt++];
					}
					b[i][j]=cnt;
					sum[cnt]+=a[i][j];
				}
			}
		}
		int64 max=LLONG_MIN,min=LLONG_MAX;
		for(register int i=1;i<=cnt;i++) {
			max=std::max(max,sum[i]);
			min=std::min(min,sum[i]);
		}
		if((max-min)*1e9/tot<ans) {
			ans=(max-min)*1e9/tot;
			sid=8;
		}
	}
	void print() {
		for(register int i=1;i<=n;i++) {
			for(register int j=1;j<=m;j++) {
				printf("%d%c",b[i][j]," \n"[j==m]);
			}
		}
	}
};
int main() {
	n=getint(),m=getint(),k=getint();
	for(register int i=1;i<=n;i++) {
		for(register int j=1;j<=m;j++) {
			a[i][j]=getint();
			avg+=a[i][j];
		}
	}
	tot=avg;
	avg/=k;
	sol01::main();
	sol02::main();
	sol03::main();
	sol04::main();
	sol05::main();
	sol06::main();
	sol07::main();
	sol08::main();
	if(sid==1) sol01::print();
	if(sid==2) sol02::print();
	if(sid==3) sol03::print();
	if(sid==4) sol04::print();
	if(sid==5) sol05::print();
	if(sid==6) sol06::print();
	if(sid==7) sol07::print();
	if(sid==8) sol08::print();
	return 0;
}
posted @ 2018-09-17 19:05  skylee03  阅读(126)  评论(0编辑  收藏  举报