14年NOI的题
通过一系列操作生成了n*n个随机数,将这些数按顺序填入一个n*n的方格,求从左上角走到右下角,能得到的字典序最小的路径。
前面直接模拟
求路径序列的时候,考虑贪心取当前能走到的最小的数一定是最优的
于是直接从1~n*n判断每个数能不能取
能则输出并删除这个数的左下角和右上角所有格子
256M只能开2个5000*5000的int和一个boolean
所以记录每个数位置时用位运算压到一个int里
其实访问标记可以不用开n方。。
//跨年卡题666 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define clr(x,i) memset(x,i,sizeof(x)) using namespace std; const int N=5002; LL seed,a,b,c,d; int t[N*N],mp[N][N],n,m,q; bool ban[N][N]; inline int r() { return seed=(a*seed*seed%d+b*seed%d+c)%d; } inline void vis(int x,int y) { //ban[x][y]=1; for(int i=x-1;i>0;i--) for(int j=y+1;j<=m;j++){ if(ban[i][j])break; ban[i][j]=1; } for(int i=x+1;i<=n;i++) for(int j=y-1;j>0;j--){ if(ban[i][j])break; ban[i][j]=1; } } int main() { scanf("%lld%lld%lld%lld%lld",&seed,&a,&b,&c,&d); scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n*m;i++) t[i]=i,swap(t[i],t[r()%i+1]); for(int i=1;i<=q;i++) { int x,y;scanf("%d%d",&x,&y); swap(t[x],t[y]); } int p=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) mp[i][j]=t[++p]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) t[mp[i][j]]=(i<<15)|j; for(int i=1;i<=n*m;i++) { int x=t[i]>>15,y=t[i]&32767; if(ban[x][y])continue; if(i!=1)putchar(' '); printf("%d",i); vis(x,y); } return 0; } 跨年夜卡在OI题上也是666