BZOJ2706 : [SDOI2012]棋盘覆盖

A类数据:

将棋盘黑白染色,相邻的点之间连边,求出二分图最大匹配即可。

B类数据:

答案为$\lfloor\frac{n^2-1}{3}\rfloor$,用FFT加速计算即可,时间复杂度$O(L\log L)$。

C类数据:

轮廓线DP,对于轮廓线上每个格子,要么为空,要么被占据,要么被占据且还要向下延伸一格。

设$f[i][j][S][k]$表示考虑到$(i,j)$,轮廓线上$m$个格子状态为$S$,转角处被占据状态为$k$时最多能放几个俄罗斯方块。

时间复杂度$O(nm3^m)$。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
char sn[200010],sm[200010],type[5];int K;
namespace SubA{
const int N=105,M=N*N,inf=~0U>>2;
int n,m,cnt,i,j,a[N][N],id[N][N],S,T,h[M],gap[M],ans;
struct E{int t,f;E*nxt,*pair;}*g[M],*d[M],pool[M*6],*cur=pool;
inline void add(int s,int t){
  if(!s||!t)return;
  E*p=cur++;p->t=t;p->f=1;p->nxt=g[s];g[s]=p;
  p=cur++;p->t=s;p->f=0;p->nxt=g[t];g[t]=p;
  g[s]->pair=g[t];g[t]->pair=g[s];
}
int sap(int v,int flow){
  if(v==T)return flow;
  int rec=0;
  for(E*p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f){
    int ret=sap(p->t,min(flow-rec,p->f));
    p->f-=ret;p->pair->f+=ret;d[v]=p;
    if((rec+=ret)==flow)return flow;
  }
  if(!(--gap[h[v]]))h[S]=T;
  gap[++h[v]]++;d[v]=g[v];
  return rec;
}
void solve(){
  sscanf(sn,"%d",&n);
  sscanf(sm,"%d",&m);
  while(K--)scanf("%d%d",&i,&j),a[i][j]=1;
  for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(!a[i][j])id[i][j]=++cnt;
  S=cnt+1;T=S+1;
  for(i=1;i<=n;i++)for(j=1;j<=m;j++)if((i+j)&1)add(S,id[i][j]);else add(id[i][j],T);
  for(i=1;i<=n;i++)for(j=1;j<=m;j++)if((i+j)&1){
    add(id[i][j],id[i][j-1]);
    add(id[i][j],id[i][j+1]);
    add(id[i][j],id[i-1][j]);
    add(id[i][j],id[i+1][j]);
  }
  for(gap[0]=T,i=1;i<=T;i++)d[i]=g[i];
  while(h[S]<T)ans+=sap(S,inf);
  printf("%d",ans);
}
}
namespace SubB{
const int N=262150;
const double pi=acos(-1.0);
struct comp{
  double r,i;comp(double _r=0,double _i=0){r=_r,i=_i;}
  comp operator+(const comp&x){return comp(r+x.r,i+x.i);}
  comp operator-(const comp&x){return comp(r-x.r,i-x.i);}
  comp operator*(const comp&x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}
  comp conj(){return comp(r,-i);}
}A[N],B[N];
int n,i,j,k,pos[N],c[N];
void FFT(comp*a,int n,int t){
  for(int i=1;i<n;i++)if(i<pos[i])swap(a[i],a[pos[i]]);
  for(int d=0;(1<<d)<n;d++){
    int m=1<<d,m2=m<<1;double o=pi*2/m2*t;comp _w(cos(o),sin(o));
    for(int i=0;i<n;i+=m2){
      comp w(1,0);
      for(int j=0;j<m;j++){
        comp&A=a[i+j+m],&B=a[i+j],t=w*A;
        A=B-t;B=B+t;w=w*_w;
      }
    }
  }
  if(t==-1)for(int i=0;i<n;i++)a[i].r/=n;
}
void solve(){
  n=strlen(sn);
  for(i=0;i<n;i++)A[i]=comp(sn[n-i-1]-‘0‘,sn[n-i-1]-‘0‘);
  for(k=1;k<n+n;k<<=1);
  j=__builtin_ctz(k)-1;
  for(i=0;i<k;i++)pos[i]=pos[i>>1]>>1|((i&1)<<j);
  FFT(A,k,1);
  for(i=0;i<k;i++){
    j=(k-i)&(k-1);
    B[i]=(A[i]*A[i]-(A[j]*A[j]).conj())*comp(0,-0.25);
  }
  FFT(B,k,-1);
  for(i=0;i<k;i++)c[i]=int(B[i].r+0.5);
  for(i=0;i<k;i++)c[i+1]+=c[i]/10,c[i]%=10;
  for(n=k;!c[n];n--);
  c[0]--;
  for(i=n;~i;i--){
    if(i)c[i-1]+=c[i]%3*10;
    c[i]/=3;
  }
  while(n&&!c[n])n--;
  for(i=n;~i;i--)printf("%d",c[i]);
}
}
namespace SubC{
const int N=11,M=180000;
int n,m,i,j,k,t,S,x,E,a[N][N],cnt,q[M],h[1<<22],f[M][2],g[M][2],ans;
inline int get(int x,int y){return x>>(y+y)&3;}
inline void clr(){for(int i=1;i<=cnt;i++)f[i][0]=f[i][1]=-1;}
inline void nxt(){for(int i=1;i<=cnt;i++)g[i][0]=f[i][0],g[i][1]=f[i][1];}
inline void up(int&x,int y){if(x<y)x=y;}
void solve(){
  sscanf(sn,"%d",&n);
  sscanf(sm,"%d",&m);
  while(K--)scanf("%d%d",&i,&j),a[i-1][j-1]=1;
  for(S=0;S<(1<<(m+m));S++){
    for(j=1,i=0;i<m;i++)if(get(S,i)==3){j=0;break;}
    if(j)q[++cnt]=S,h[S]=cnt;
  }
  clr();
  nxt();
  for(S=i=0;i<m;i++)S|=1<<(i+i);
  g[h[S]][0]=0;
  for(i=0;i<n;i++)for(j=0;j<m;j++){
    clr();
    for(k=1;k<=cnt;k++)for(t=0;t<2;t++)if(~g[k][t]){
      S=q[k],x=get(S,j),E=S^(x<<(j+j));
      if(x==2){
        if(a[i][j])continue;
        up(f[h[E^(1<<(j+j))]][x>0],g[k][t]);
      }else{
        up(f[h[E]][x>0],g[k][t]);
        if(a[i][j])continue;
        if(i>0)if(!x&&!a[i-1][j])up(f[h[E^(2<<(j+j))]][1],g[k][t]+1);
        if(j>=2)if(!get(S,j-1)&&!a[i][j-1]&&!get(S,j-2)&&!a[i][j-2]){
          up(f[h[E^(1<<(j+j-4)^(1<<(j+j-2)^(1<<(j+j))))]][x>0],g[k][t]+1);
        }
        if(j>=1)if(!get(S,j-1)&&!a[i][j-1]){
          up(f[h[E^(2<<(j+j-2))^(1<<(j+j))]][x>0],g[k][t]+1);
          up(f[h[E^(1<<(j+j-2))^(2<<(j+j))]][x>0],g[k][t]+1);
          if(i>0){
            if(!t&&!a[i-1][j-1]){
              up(f[h[E^(1<<(j+j-2))^(1<<(j+j))]][x>0],g[k][t]+1);
            }
            if(!x&&!a[i-1][j]){
              up(f[h[E^(1<<(j+j-2))^(1<<(j+j))]][1],g[k][t]+1);
            }
          }
        }
      }
    }
    nxt();
  }
  for(k=1;k<=cnt;k++){
    S=q[k];
    for(j=1,i=0;i<m;i++)if(get(S,i)==2){j=0;break;}
    if(j)for(t=0;t<2;t++)up(ans,g[k][t]);
  }
  printf("%d",ans);
}
}
int main(){
  scanf("%s%s%d%s",sm,sn,&K,type);
  if(type[0]==‘A‘)SubA::solve();
  if(type[0]==‘B‘)SubB::solve();
  if(type[0]==‘C‘)SubC::solve();
  return 0;
}

  

时间: 2024-11-16 14:52:02

BZOJ2706 : [SDOI2012]棋盘覆盖的相关文章

bzoj 2706: [SDOI2012]棋盘覆盖 Dancing Link

2706: [SDOI2012]棋盘覆盖 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 255  Solved: 77[Submit][Status] Description 在一个N*M个方格组成的棋盘内,有K个方格被称为特殊方格.我们要使用一组俄罗斯方块来覆盖这个棋盘,保证特殊方格不能被覆盖,非特殊方格只能被一个俄罗斯方块覆盖,求最多能容纳的俄罗斯方块的数量. 已知有以下三组俄罗斯方块,一个棋盘可能用其中的某一组. Input 第一行三个整数

棋盘覆盖问题

棋盘覆盖问题       问题描述: 在一个2^k×2^k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘.显然特殊方格在棋盘上出现的位置有4^k种情形.因而对任何k≥0,有4^k种不同的特殊棋盘.     下图–图(1)中的特殊棋盘是当k=3时16个特殊棋盘中的一个: 图(1) 题目要求在棋盘覆盖问题中,要用下图-图(2)所示的4种不同形态的L型骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖. 图(2) 题目

计算机算法设计与分析之棋盘覆盖问题

一.引子 最近又重新上了算法课,现在想来有点汗颜,大学期间已经学习了一个学期,到现在却依然感觉只是把老师讲过的题目弄懂了,并没有学到算法的一些好的分析方法和思路,碰到一个新的问题后往往感觉很棘手,痛定思痛之后觉得还是好好再学习一遍,争取能理解透彻每种算法的思路和核心,同时也劝诫各位同行们做事要脚踏实地,不能应付老师的作业,最后吃亏的还是自己啊. 二.棋盘覆盖问题 在一个由2^k *2^k个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘 为一特殊棋盘.现有四种L型骨

nyoj 45 棋盘覆盖

棋盘覆盖 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 在一个2k×2k(1<=k<=100)的棋盘中恰有一方格被覆盖,如图1(k=2时),现用一缺角的2×2方格(图2为其中缺右下角的一个),去覆盖2k×2k未被覆盖过的方格,求需要类似图2方格总的个数s.如k=1时,s=1;k=2时,s=5 输入 第一行m表示有m组测试数据: 每一组测试数据的第一行有一个整数数k; 输出 输出所需个数s; 样例输入 3 1 2 3 样例输出 1 5 21 /* 注意寻找图中规律

棋盘覆盖(大数阶乘,大数相除)

棋盘覆盖 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 在一个2k×2k(1<=k<=100)的棋盘中恰有一方格被覆盖,如图1(k=2时),现用一缺角的2×2方格(图2为其中缺右下角的一个),去覆盖2k×2k未被覆盖过的方格,求需要类似图2方格总的个数s.如k=1时,s=1;k=2时,s=5 图1 图2 输入 第一行m表示有m组测试数据:每一组测试数据的第一行有一个整数数k; 输出 输出所需个数s; 样例输入 3 1 2 3 样例输出 1 5 21 accept

算法实验--棋盘覆盖

一.实验目的: 熟悉掌握分治算法设计技术 二.实验要求: 1.按教材所授内容要求,完成“棋盘覆盖问题”算法.得到一个完整正确的程序. 2.棋盘大小:32*32(或16*16) 3.输出最终结果. 三.实验设备及环境: PC机一台.java虚拟机Eclipse或jdk环境 四.问题描述: 通过一门语言写一个棋盘覆盖算法,并对棋盘着色,使L型骨牌能够使用相同的颜色,能够在棋盘中一眼看出棋子所在的地方和对棋盘着色的效果. 五.算法分析: 添加               按钮 对象          

js算法:分治法-棋盘覆盖

在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其他方格不同.则称该方格为一特殊方格,称该棋盘为一特殊棋盘.显然特殊方格在棋盘上出现的位置有 4^k 种情形.因而对不论什么 k>=0 .有 4^k 种不同的特殊棋盘. 下图所看到的的特殊棋盘为 k=2 时 16 个特殊棋盘中的一个. 在棋盘覆盖问题中,要用下图中 4 中不同形态的 L 型骨牌覆盖一个给定的特殊棋牌上除特殊方格以外的全部方格,且不论什么 2 个 L 型骨牌不得重叠覆盖. 易知,在不论什么一个 2^k * 2^k 的棋

算法之棋盘覆盖

棋盘覆盖分析与实现 一.什么是棋盘覆盖? 首先来了解什么是特殊方格在一个2^k*2^k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为特殊方格,显然,特殊方格出现的位置有4^k种情况,即k>=0,有4^k种不同的特殊棋盘 棋盘覆盖:用4种不同的L型骨牌覆盖一个给定的特殊棋盘(即特殊方格的位置已经确定了)上除去特殊方格外的所有方格,且任何两个L型骨牌不得重复覆盖,按照规则,我们很容易知道,在2^k*2^k的棋盘覆盖中,用到的L型骨盘数恰为(4^k-1)/3,即(所有方格个数-特殊方格

【棋盘覆盖】(简单)--分治算法

算法实验1:棋盘覆盖 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 2798  Solved: 702 [Submit][Status][Discuss] Description 在一个2k x 2k 个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘.在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖. 口