[贪心] BZOJ 3671 [Noi2014]随机数生成器

这题因为要求是字典序最小

所以就可以贪心。一位位取看能不能取到。

取的时候把取的这个数左下右上标记成不可取就行了。

均摊复杂度O(NM) 类似筛法的复杂度


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(ll &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

int n,m;
ll a,b,c,d;
int x[25000005];
int num[5005][5005];
int ans[10005],pnt;

inline int Mul(int a,int b){
	int ret=0;
	for (;b;b>>=1,a=(a+a)%d)
		if (b&1)
			(ret+=a)%=d;
	return ret;
}

inline int P(int x,int y){
	return (x-1)*m+y;
}

inline void Swp(int u,int v){
	int x1,y1,x2,y2;
	x1=(u-1)/m+1; x2=(v-1)/m+1;
	y1=(u-1)%m+1; y2=(v-1)%m+1;
	swap(num[x1][y1],num[x2][y2]);
}

int main()
{
	int Q,u,v,ix,iy,s,t;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(x[0]); read(a); read(b); read(c); read(d);
	a%=d; b%=d; c%=d;
	read(n); read(m);
	for (int i=1;i<=n*m;i++)
		x[i]=(a*x[i-1]*x[i-1]+b*x[i-1]+c)%d;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			num[i][j]=P(i,j);
	for (int i=1;i<=n*m;i++)
		Swp(i,x[i]%i+1);
	read(Q);
	while (Q--)
		read(u),read(v),Swp(u,v);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			x[num[i][j]]=P(i,j);
	cl(num);
	for (int i=1;i<=n*m;i++)
	{
		ix=(x[i]-1)/m+1; iy=(x[i]-1)%m+1;
		if (num[ix][iy])
			continue;
		ans[++pnt]=i;
		if (pnt==n+m-1) break;
		s=1;  
        t=iy-1;
		int ii,jj; 
        for(ii=ix+1;ii<=n && s<=t;ii++,s=jj+1)
            for(jj=t;jj>=s && !num[ii][jj];jj--)
            	num[ii][jj]=1;
        s=iy+1;  
        t=m;  
        for(ii=ix-1;ii>=1 && s<=t;ii--,t=jj-1)  
            for(jj=s;jj<=t && !num[ii][jj];jj++)
                num[ii][jj]=1;   
	}
	for (int i=1;i<=pnt;i++)
		i==pnt?printf("%d\n",ans[i]):printf("%d ",ans[i]);
	return 0;
}


你可能感兴趣的:([贪心] BZOJ 3671 [Noi2014]随机数生成器)