来自FallDream 的博客,未经允许,请勿转载, 谢谢。
n,m<=5000
前面生成的一堆数列 意义不明 实际上就是给你一个矩阵求排序后字典序最小的路径序列
发现(1,1)->(n,m)在选了(x,y)之后就变成了选(1,1)->(x,y)和(x,y)->(n,m)
所以直接从1开始贪心,能选就选,用数组维护一下每一行可选的左右区间就行了。
但是我菜 所以我写了一个set维护矩形,然后二分..
#include<iostream> #include<cstdio> #include<set> #include<algorithm> #define MN 25000000 using namespace std; inline int read() {int x = 0 , f = 1; char ch = getchar();while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f; }int tot,x,a,b,c,d,n,m,q,s[MN+1],pos[MN+1],Q[10001],top=0; struct sq{int x1,y1,x2,y2;bool operator<(const sq&b)const{return y2==b.y2?x2<b.x2:y2<b.y2;}bool in(int x,int y)const{return x>=x1&&x<=x2&&y>=y1&&y<=y2;} }; set<sq> st; bool mark[MN+1]; int main() {x=read();a=read();b=read();c=read();d=read();n=read();m=read();tot=n*m;q=read();for(register int i=1;i<=tot;++i) s[i]=i;for(register int i=1;i<=tot;++i)x=(1LL*a*x*x+1LL*b*x+c)%d,swap(s[i],s[x%i+1]);for(register int i=1;i<=q;++i) {int x=read(),y=read();swap(s[x],s[y]); }for(register int i=1;i<=tot;++i) pos[s[i]]=i;mark[Q[++top]=s[1]]=1;mark[Q[++top]=s[tot]]=1;st.insert((sq){1,1,n,m});for(register int i=1;i<=tot;++i) if(!mark[i]){int x=(pos[i]-1)/m+1,y=(pos[i]-1)%m+1;set<sq>::iterator it = st.lower_bound((sq){0,0,x,y});if(it->y2==y&&it->x2<x) ++it;if(it!=st.end()&&it->in(x,y)){Q[++top]=i;sq th=*it;st.erase(it);if(th.x1!=x||th.y1!=y)st.insert((sq){th.x1,th.y1,x,y});if(th.x2!=x||th.y2!=y)st.insert((sq){x,y,th.x2,th.y2});for(register int j=x+1;j<=th.x2;++j)for(register int k=th.y1;k<y;++k)mark[s[(j-1)*m+k]]=1;for(register int j=th.x1;j<x;++j)for(register int k=y+1;k<=th.y2;++k)mark[s[(j-1)*m+k]]=1;}}sort(Q+1,Q+top+1);printf("%d",Q[1]);for(register int i=2;i<=top;++i) printf(" %d",Q[i]);\return 0; }