题解 [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;
}
浙公网安备 33010602011771号