点击这里查看原题
很显然,贪心的去想,要使字典序最小,那么每次应从可以取的数中取最小的数,然后取完对左下和右上的部分标记,因为每个点只会被标记一次(遇到标记过的点就break),所以复杂度O(nm)
/*
User:Small
Language:C++
Problem No.:6
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=5e3+5;
int num[M*M],a,b,c,d,n,m,q,pos[M*M],ans[2*M],tot;
bool vis[M][M];
int main(){
freopen("data.in","r",stdin);//
scanf("%d%d%d%d%d%d%d%d",&pos[0],&a,&b,&c,&d,&n,&m,&q);
for(int i=1;i<=n*m;i++) num[i]=i;
for(int i=1;i<=n*m;i++) pos[i]=((ll)a*pos[i-1]%d*pos[i-1]%d+(ll)b*pos[i-1]%d+c)%d;
for(int i=1;i<=n*m;i++) swap(num[i],num[pos[i]%i+1]);
while(q--){
int u,v;
scanf("%d%d",&u,&v);
swap(num[u],num[v]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
pos[num[(i-1)*m+j]]=(i-1)*m+j;
}
for(int a=1;a<=n*m;a++){
int x=pos[a]/m+1,y=pos[a]%m;
if(y==0) y=m,x--;
if(vis[x][y]) continue;
ans[++tot]=a;
int s=1,t=y-1;
for(int i=x+1;i<=n;i++){
if(vis[i][t]) break;
for(int j=t;j>=s;j--){
if(vis[i][j]){
s=j+1;
break;
}
vis[i][j]=1;
}
if(t<s) break;
}
s=y+1,t=m;
for(int i=x-1;i;i--){
if(vis[i][s]) break;
for(int j=s;j<=t;j++){
if(vis[i][j]){
t=j-1;
break;
}
vis[i][j]=1;
}
if(s>t) break;
}
}
printf("%d",ans[1]);
for(int i=2;i<=tot;i++) printf(" %d",ans[i]);
printf("\n");
return 0;
}