• [ZJOI 2005] 梦幻折纸


    题目传送-Luogu

    题意:

    给一个 (n*m) 的网格图,每个网格上有 ([1,n*m]) 的数字,且每个都出现且恰好出现一次.
    显然进行若干次折叠直到剩下一个 (1*1) 的小网格时,它在纵向上有 (n*m) 层.
    那么能否安排一种折叠方案,使得这 (n*m) 层从上往下的标号恰好为 (1)(n*m).

    题解:

    显然每个纵向和横向的格线都会被折到.我们观察剩下的的那个小方格,可以发现每层都有向左或右,上或下的连接,而且上下的连接和左右的连接是无关的.
    然而还是没有什么卵用...
    这时我们考虑什么情况下会不存在合法的方案,先举个例子:1 3 4 2.
    我们想象面前有个 (1*4) 的纸条,先把 3 折到 1 的下面,再把 4 折到 3 的下面,这时我们发现 2 居然折不进去了.
    这是因为 (4,2)(1,3) 的连接是同向的,那么这样就不能交叉进去了.
    那么我们发现折痕的方向是相邻的格线两两相反的(折一折就知道了)
    根据上面的结论,相同的方向的折痕不能存在相交.这样我们就会只有一条的情况了.

    对于一般情况,我们发现当一条格线被决策后,它所在的所有格子都会被强制决策.
    由于行和列是互不影响的,那么这个就很好扩展了.

    过程:

    想了超级久的..

    代码:

    #define GG {puts("Cheat"); continue;}
    const int N=110;
    int n,m;
    int G[N][N];
    struct SEG {
      int L,R;
      inline void Config() {
        if(L>R) swap(L,R);
      }
      inline void Print() {
        printf("%d %d
    ",L,R);
      }
      bool operator < (const SEG &a)const {
        return L<a.L;
      }
    };
    vector<SEG> seg[2];
    inline bool Judge() {
      //printf("Start
    ");
      for(int t=0;t<2;t++) {
        sort(seg[t].begin(),seg[t].end());
        //for(int i=0;i<(int)seg[t].size();i++) seg[t][i].Print();
        vector<pii> ref;
        for(int i=0;i<(int)seg[t].size();i++) {
          ref.pb(mp(seg[t][i].L,i+1));
          ref.pb(mp(seg[t][i].R,-i-1));
        }
        sort(ref.begin(),ref.end());
        assert(ref.size()==seg[t].size()*2);
        stack<int> stk;
        for(int i=0;i<(int)ref.size();i++) {
          //printf("Ask::%d %d
    ",ref[i].F,ref[i].S);
          if(ref[i].S>0) stk.push(ref[i].S);
          else {
    	if(stk.top()!=-ref[i].S) return false;
    	stk.pop();
          }
        }
      }
      return true;
    }
    signed main() {
      int T; read(T);
      for(int cas=1;cas<=T;cas++) {
        read(n); read(m);
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
    	read(G[i][j]);
        seg[0].clear(); seg[1].clear();
        for(int i=1;i<n;i++)
          for(int j=1;j<=m;j++)
    	seg[i&1].pb((SEG){G[i][j],G[i+1][j]});
        for(int i=0;i<2;i++)
          for(int j=0;j<(int)seg[i].size();j++)
    	seg[i][j].Config();
        if(!Judge()) GG;
    
        seg[0].clear(); seg[1].clear();
        for(int j=1;j<m;j++)
          for(int i=1;i<=n;i++)
    	seg[j&1].pb((SEG){G[i][j],G[i][j+1]});
        for(int i=0;i<2;i++)
          for(int j=0;j<(int)seg[i].size();j++)
    	seg[i][j].Config();
        if(!Judge()) GG;
        puts("AllRight");
      }
      return 0;
    }
    

    用时: (infty)

  • 相关阅读:
    简单bb两句
    P2894 [USACO08FEB]Hotel G
    文艺平衡树
    CS184.1X 计算机图形学导论作业1
    C++ Primer Plus章节编程练习(第五章)
    C++ Primer Plus章节编程练习(第六章)
    CS184.1X 计算机图形学导论作业0
    C++ Primer Plus章节编程练习(第四章)
    计算机图形学之光栅图形学算法
    Codeforces 980B
  • 原文地址:https://www.cnblogs.com/functionendless/p/10622780.html
Copyright © 2020-2023  润新知