来自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; }