题解 P2354 【[NOI2014]随机数生成器】
ImmortalWatcher · · 题解
说在前面
做之前:
做之后:好吧,还真应该降为紫题。
Description
题目好像说这么多没啥用,还是简化一下。
给你五个数
输入
然后你要对
交换
最后输入
输入
接着把
问:
从左上角走到右下角组成的序列排序后最小字典序的序列是什么?
Solution
其实不要被紫题所迷惑,其实这就是一道简单的贪心题。
由于要求字典序最小,所以我们肯定能走最小就走最小。
我们可以预处理出
如果能选,就要修改相应不能选的位置:
设
因为从(x,y)不可能再走到红色区域。然后依次修改l,r即可。
Code
#include<cstdio>
#include<algorithm>
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
using namespace std;
int n,m,q,x[25000001],t[25000001],u,v,l[5001],r[5001],tot;
long long a,b,c,d;
int main()
{
scanf("%d%lld%lld%lld%lld",&x[0],&a,&b,&c,&d);
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n*m;i++)
x[i]=(x[i-1]*(a*x[i-1]+b)+c)%d,t[i]=i;
for (int i=1;i<=n*m;i++)
swap(t[i],t[x[i]%i+1]);
for (int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
swap(t[u],t[v]);
}
for (int i=1;i<=n*m;i++)
x[t[i]]=i;
for (int i=1;i<=n;i++)
l[i]=1,r[i]=m;
for (int i=1;i<=n*m;i++)
{
int xx,yy;
if (x[i]%m==0) xx=x[i]/m;
else xx=x[i]/m+1;
yy=x[i]%m;
if (!yy) yy=m;
if (yy>=l[xx]&&yy<=r[xx])
{
++tot;
printf("%d ",i);
if (tot==n+m-1) return 0;
for (int j=1;j<=n;j++)
if (j<xx) r[j]=min(r[j],yy);
else if (j>xx) l[j]=max(l[j],yy);
}
}
return 0;
}
最后注意一下空间,可以把
祝大家早日