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