题解 [NOI2014] 随机数生成器

传送门

专题里放错题了吧?

发现就一模拟
贪心选数的时候在值域上从小到大选
选了一个数后位置在它左下和右上的权值都不能选
发现这两个覆盖分别有单调性,分别开个数组存
然后发现可以用一个值在 \(T\) 中的下标还原其位置
然后就做完了
复杂度 \(O(nm)\),常数莫名其妙的大

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 5010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, q;
ll x0, a, b, c, d;
int t[N*N], id[N*N], lim, top;
bitset<N> vis1[N], vis2[N];

inline pair<int, int> pos(int id) {
	if (id%m==0) return {id/m, m};
	else return {id/m+1, id%m};
}

signed main()
{
	x0=read(); a=read(); b=read(); c=read(); d=read();
	n=read(); m=read(); q=read(); lim=n*m;
	for (int i=1; i<=lim; ++i) t[i]=i;
	for (int i=1; i<=lim; ++i) {
		x0=(a*x0*x0+b*x0+c)%d;
		swap(t[i], t[x0%i+1]);
	}
	for (int i=1,u,v; i<=q; ++i) {
		u=read(); v=read();
		swap(t[u], t[v]);
	}
	for (int i=1; i<=lim; ++i) id[t[i]]=i;
	// for (int i=1; i<=n; ++i)
	// 	for (int j=1; j<=m; ++j)
	// 		assert(pos((i-1)*m+j)==make_pair(i, j));
	for (int i=1; i<=lim; ++i) {
		pair<int, int> p=pos(id[i]);
		if (vis1[p.fir][p.sec]||vis2[p.fir][p.sec]) continue;
		t[++top]=i;
		for (int i=p.fir+1; i<=n; ++i)
			for (int j=p.sec-1; j&&!vis1[i][j]; --j)
				vis1[i][j]=1;
		for (int i=p.fir-1; i; --i)
			for (int j=p.sec+1; j<=m&&!vis2[i][j]; ++j)
				vis2[i][j]=1;
	}
	sort(t+1, t+top+1);
	for (int i=1; i<=top; ++i) printf("%d%c", t[i], " \n"[i==top]);

	return 0;
}
posted @ 2022-06-15 17:13  Administrator-09  阅读(7)  评论(0)    收藏  举报