【CF1428D】Bouncing Boomerangs 题解

原题链接

题意简介

毒瘤大模拟

给你一张n*n的图,在图上摆有一些物体。从每一列的底端往上扔回旋镖,每镖中一个东西,回旋镖就会向右转九十度。现在我们知道从每列i底端往上镖时撞上的物体个数ai,试构造出一个合法的图。若无法构造出这样的图,输出-1。

原题配图

需要注意的是,题目有几个重要的约束条件

  • \(a_i\leq3\)
  • 每一行和每一列上的物品的个数不能超过2

思路分析

以下纯属个人看法。

要构造出一种符合题意的图,我们希望在构造过程中消耗的行和列尽可能少。

换句话说,我们希望能尽可能实现物体的“共用”。因为共用的话就不需要再开一行、一列了。

接下来考虑什么样的情况可以“共用”。我们令 \(i<j\) :

  1. \(a_j=1\) 时,若 \(a_i>1\) 则j所需要的物品可以与i共用。
  2. \(a_j=2\) 时,若 \(a_i>2\) 则j所需要的第一个物品可以与i共用。需要注意 \(a_i=2\) 的情况是不行的,因为每行最多只能有两个物体。
  3. \(a_j=3\) 时,若 \(a_i=3\) 则j所需要的第一个物品可以与i共用。需要注意出现在后面的3是不可能与前面的2共用的,因为若共用,只可能共用2的第二个物体,而这个物体与2的第一个物体在同一行上,若共用的话会撞上它,有 \(a_j>3\) ,不满足题意。

接下来考虑各种情况对空余行和列的数量的影响:
(下面的分析主要取决于影响的统计顺序,不同的统计方式可能会有不同的结论,此处只列出我的做法)

  1. \(a_j=0\) 时,空余列减1,因为这一列上不能放任何东西
  2. \(a_j=1\) 时,若与前面的某个i“共用”一个物体,由于已经在i处统计过了,所以不用重复统计影响;若没有共用,则空余行、空余列都要减1。因为我们是往右扫的,\(a_j=1\) 意味着这一行后面没有撞上东西。至于列,由于前面没有共用,且回旋镖只会往右转且最多打到3个物体,所以后面不可能再有某个k与这个j共用了。
  3. \(a_j=2\) 时,若与前面的某个i共用,\(a_i\) 一定等于3,由于已经在i处统计过了,所以只需空余列减1;若没有共用,则空余行减1、空余列减2
  4. \(a_j=3\) 时,若与前面的某个i共用,\(a_i\) 一定等于3,由于已经在i处统计过了,所以只需空余行减1且空余列减1;若没有共用,则空余行减2、空余列减2

其实只要画个图,上面这些结论都可以很快得出。

一轮扫描,先确定每一个回旋镖的共用(拼接)顺序。假若扫描后出现空余列或空余行比0小的情况,就直接输出-1即可。

接下来需要考虑如何根据拼接顺序还原图。

我们知道,每个 \(a_i=2\) 后面必然且只能接一个 \(a_j=1\) ,接2或3的话会使 \(a_i=3\)
对于 \(a_i=3\) 的情形,我们需要的行数是最多的,所以我们不妨把这样的物体从最顶行设起
对于 \(a_i=2 or a_i=1\) 的情形,我们不需要在行的下面再放物品了,不妨从最底行设起,把上面广阔的空间留给需要预留出一行的3。

注意观察图片 最顶行是1 最底行是n

下面给出几组我错过的数据可供测试(如果懒得去cf翻的话) 答案可以自己手推一下合不合理。

数据1:

4
3 3 1 1

数据2:

4
3 3 3 1

其实我主要是错在对行列处理的分类讨论上 还有对3的行分配上。这是需要注意的。

接下来就是实现,具体的一些小细节在代码中有体现,此处不再做赘述。

代码库

#include <cstdio>
const int N=1e5+5;
int n,a[N],pre[N],st2[N],st3[N],s2,s3,line,col,nex[N];
int ans[N<<1][2],cnt; bool vis[N];
inline bool is1(int i){
    if(nex[i]) return a[nex[i]]!=3;
    return a[i]==1;
}
int main(){
    scanf("%d",&n); line=col=n;
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=n;i++){
        if(a[i]==0){
            col--; continue;
        }
        if(a[i]==1){
            if(s2) pre[i]=st2[s2--],nex[pre[i]]=i;
            else if(s3) pre[i]=st3[s3--],nex[pre[i]]=i;
            else line--,col--;
            continue;
        }
        if(a[i]==2){
            if(s3) pre[i]=st3[s3--],nex[pre[i]]=i,col--,st2[++s2]=i;
            else line--,col-=2,st2[++s2]=i;
            continue;
        }
        if(a[i]==3){
            if(s3) pre[i]=st3[s3--],nex[pre[i]]=i,line--,col--,st3[++s3]=i;
            else line-=2,col-=2,st3[++s3]=i;
            continue;
        }
    }
    if(line<0||col<0){
        printf("-1\n"); return 0;
    }
    int top=0,low=n+1;
    for(int i=1;i<=n;i++){
        if(vis[i]||!a[i]) continue;
        for(int j=i;j;j=nex[j]){
            //printf("Calc %d:%d %d\n",j,top,low);
            vis[j]=1;
            if(a[j]==1){
                if(!pre[j]) ans[++cnt][0]=--low,ans[cnt][1]=j;
                //printf("Calc %d:%d %d\n",j,top,low);
                continue;
            }
            if(a[j]==2){
                if(!pre[j]){
                    if(is1(j)) ans[++cnt][0]=--low,ans[cnt][1]=j;
                    else ans[++cnt][0]=++top,ans[cnt][1]=j;
                }
                cnt++;
                ans[cnt][0]=ans[cnt-1][0]; ans[cnt][1]=nex[j];
                //printf("Calc %d:%d %d\n",j,top,low);
                continue;
            }
            if(a[j]==3){
                if(!pre[j]){
                    if(is1(j)) ans[++cnt][0]=low-2,ans[cnt][1]=j;
                    else ans[++cnt][0]=++top,ans[cnt][1]=j;
                }
                cnt++;
                ans[cnt][0]=ans[cnt-1][0]; ans[cnt][1]=nex[j];
                cnt++;
                if(!pre[j]&&is1(j)) ans[cnt][0]=--low,ans[cnt][1]=nex[j],low--;
                else if(is1(j)) ans[cnt][0]=--low,ans[cnt][1]=nex[j];
                else ans[cnt][0]=++top,ans[cnt][1]=nex[j];
                //printf("Calc %d:%d %d\n",j,top,low);
                continue;
            }
        }
    }
    //printf("End with %d %d\n",top,low);
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i][0],ans[i][1]);
    //for(int i=1;i<=n;i++) if(a[i]!=1&&a[i]!=0&&nex[i]==0) printf("ERR %d!\n",i); 
    return 0;
}

END

posted @ 2020-10-18 09:59  喵乖乖喵  阅读(282)  评论(0编辑  收藏  举报

膜拜众神

网安院技术部     ZZY大师     Xinyang 大佬     Wjyyy