BZOJ3671 NOI2014随机数生成器 贪心+暴力

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



猜你喜欢

转载自blog.csdn.net/wolf_reiser/article/details/78965084