【BZOJ】【P3671】【NOI2014】【随机数生成器】【题解】【贪心】

传送门:www.lydsy.com:808/JudgeOnline/problem.php?id=3671

从hzwer神犇那看到的题解,第一眼:卧槽n^2m复杂度能过?测了测果然能过,第二眼:卧槽O(n^2+nm)的sb贪心啊,想好了就是noip难度的……

首先从小到大贪心,能走就走,然后问题就在于如何判断是否可行,蒟蒻考场上写了二维树状数组……60……其实记录一下每一列的可行区域就可以了……哇……哭瞎了

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5001;
int n,m,q;
long long x,a,b,c,d;
int getint(){
	int res=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))(res*=10)+=ch-'0',ch=getchar();
	return res;
}
int rnd(){
	return x=(x*(a*x+b)+c)%d;
}
int t[maxn*maxn];
int pos[maxn*maxn];
int up[maxn],down[maxn];
int main(){
	x=getint();a=getint();
	b=getint();c=getint();
	d=getint();n=getint();
	m=getint();q=getint();
	for(int i=1;i<=n*m;i++)t[i]=i;
	for(int i=1;i<=n;i++)up[i]=m,down[i]=1;
	for(int i=1;i<=n*m;i++)swap(t[i],t[(rnd()%i)+1]);
	for(int i=1;i<=q;i++){
		int u=getint(),v=getint();
		swap(t[u],t[v]);
	}
	for(int i=1;i<=n*m;i++)pos[t[i]]=i;
	int x,y,tot=0;
	for(int i=1;i<=n*m;i++){
		if(pos[i]%m)x=pos[i]/m+1;else x=pos[i]/m;
		y=pos[i]%m?pos[i]%m:m;
		if(y<=up[x]&&y>=down[x]){
        	for(int j=1;j<=n;j++)
        	if(j<x)up[j]=min(y,up[j]);
        	else if(j>x)down[j]=max(y,down[j]);
        	tot++;
        	printf("%d%c",i," \n"[tot==n+m-1]);\\drcow神犇的换行方式
			if(tot==n+m-1)break;
		}
	}
	
	return 0;
}


你可能感兴趣的:(bzoj,省选)