[构造] Codeforces Gym 101173 CERC 16 D & BZOJ 4790 Dancing Disks

本文介绍了一种基于递归思想的网格排序算法,该算法通过将网格中的元素按大小分配到不同的区块来实现最大数量的排序。文章详细阐述了算法的具体实现过程,并提供了完整的代码示例。

FB!
这里写图片描述

懒 直接搬题解吧
先令fn,m表示nm的网格能排序的最大数量
我们把左上角这一格里的数 按大小分到其他块中 其中(i,j)最多放fni+1,mj+1个 然后递归的做就好了
我们发现某根柱子就算本来有东西也毫不影响 踩上去就是了
这样是

fn,m=i=1nj=1mfi,j     in or jmf1,1=1

这样f6,6是2w+ 还不够
但是这样就可以4w+辣
fn,m=i=1nj=1mfi,j     in or jmf1,1=1,f1,2=f2,1=2

这里写图片描述
这里写图片描述

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;

#define read(x) scanf("%d",&(x))

inline void write(int x) {
  if (!x) return (void) printf("0");
  if (x < 0) putchar('-'), x = -x;
  static short s[12], t;
  while (x) s[++t] = x % 10, x /= 10;
  while (t) putchar('0' + s[t--]);
}

const int f[7][7]={
  {0,0,0,0,0,0,0},
  {0,1,2,3,6,12,24},
  {0,2,5,13,32,76,176},
  {0,3,13,42,122,332,864},
  {0,6,32,122,404,1228,3520},
  {0,12,76,332,1228,4104,12792},
  {0,24,176,864,3520,12792,42960}
};

inline void P(int x,int y,char c,int z){
  printf("%d %d %c %d\n",x,y,c,z);
}
inline void move(int x1,int y1,int x2,int y2){
  while (x1<x2) P(x1,y1,'D',1),x1++;
  while (y1<y2) P(x1,y1,'R',1),y1++;
}

const int N=40005;

int pre[7][7];
int px[N],py[N];

inline void Solve(int x,int y,int n,int m,vector<int> &v){
  if (n*m==1) return;
  if (n*m==2){
    if (v.size()==1) P(x,y,n==1?'R':'D',1);
    else{
      if (v[0]==2) P(x,y,n==1?'R':'D',2);
      else P(x,y,n==1?'R':'D',1),P(x,y,n==1?'R':'D',1);
    }
    return;
  }
  vector<int> _v[7][7];
  int pt=v.size();
  for (int i=n;i && pt;i--)
    for (int j=m;j && pt;j--){
      if (i*j==1) continue;
      int f=min(::f[n-i+1][m-j+1],pt);
      for (int k=1;k<=f;k++) px[pt]=i,py[pt]=j,pt--;
      pre[i][j]=pt;
    }
  for (int i=(int)v.size()-1;~i;i--){
    int t=v[i];
    move(x,y,x+px[t]-1,y+py[t]-1);
    _v[px[t]][py[t]].pb(t-pre[px[t]][py[t]]);
  }
  for (int i=n;i;i--)
    for (int j=m;j;j--)
      if (_v[i][j].size())
    Solve(x+i-1,y+j-1,n-i+1,m-j+1,_v[i][j]);
}

int main(){
  int a,n;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n);
  vector<int> v;
  for (int i=1;i<=n;i++) read(a),v.pb(a);
  Solve(1,1,6,6,v);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值