这题因为要求是字典序最小
所以就可以贪心。一位位取看能不能取到。
取的时候把取的这个数左下右上标记成不可取就行了。
均摊复杂度O(NM) 类似筛法的复杂度
#include<cstdio> #include<cstdlib> #include<algorithm> #include<set> #include<cstring> #define cl(x) memset(x,0,sizeof(x)) using namespace std; typedef long long ll; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(ll &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } int n,m; ll a,b,c,d; int x[25000005]; int num[5005][5005]; int ans[10005],pnt; inline int Mul(int a,int b){ int ret=0; for (;b;b>>=1,a=(a+a)%d) if (b&1) (ret+=a)%=d; return ret; } inline int P(int x,int y){ return (x-1)*m+y; } inline void Swp(int u,int v){ int x1,y1,x2,y2; x1=(u-1)/m+1; x2=(v-1)/m+1; y1=(u-1)%m+1; y2=(v-1)%m+1; swap(num[x1][y1],num[x2][y2]); } int main() { int Q,u,v,ix,iy,s,t; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(x[0]); read(a); read(b); read(c); read(d); a%=d; b%=d; c%=d; read(n); read(m); for (int i=1;i<=n*m;i++) x[i]=(a*x[i-1]*x[i-1]+b*x[i-1]+c)%d; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) num[i][j]=P(i,j); for (int i=1;i<=n*m;i++) Swp(i,x[i]%i+1); read(Q); while (Q--) read(u),read(v),Swp(u,v); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) x[num[i][j]]=P(i,j); cl(num); for (int i=1;i<=n*m;i++) { ix=(x[i]-1)/m+1; iy=(x[i]-1)%m+1; if (num[ix][iy]) continue; ans[++pnt]=i; if (pnt==n+m-1) break; s=1; t=iy-1; int ii,jj; for(ii=ix+1;ii<=n && s<=t;ii++,s=jj+1) for(jj=t;jj>=s && !num[ii][jj];jj--) num[ii][jj]=1; s=iy+1; t=m; for(ii=ix-1;ii>=1 && s<=t;ii--,t=jj-1) for(jj=s;jj<=t && !num[ii][jj];jj++) num[ii][jj]=1; } for (int i=1;i<=pnt;i++) i==pnt?printf("%d\n",ans[i]):printf("%d ",ans[i]); return 0; }