1. 程式人生 > >nowcoder 211B - 列隊 - [(偽·良心貪心)真·毒瘤暴力]

nowcoder 211B - 列隊 - [(偽·良心貪心)真·毒瘤暴力]

題目連結:https://www.nowcoder.com/acm/contest/211/B

題目描述
炎熱的早上,gal男神們被迫再操場上列隊,gal男神們本來想排列成x∗x的正方形,可是因為操場太小了(也可能是gal男神太大了),校長安排gal男神們站成多個4∗4的正方形(gal男神們可以正好分成n個正方形)但是有些gal男神對於這種站法頗有微詞,所以他們把衣服脫下來拿在手上搖晃示威,站在一條直線上的gal男神可以“交頭接耳”,交頭接耳會使他們聯合起來鬧事,人數越多,威脅程度就越大。你作為也反對這種站隊方式的體育老師,為了助紂為虐,應該以一種“合理”的方式來排布n個gal男神方陣,使得最大的威脅程度最大。輸出這個威脅程度。
以下為化簡版題幹:
現在有n個由0和1組成的4∗4矩陣,你可以任意排列這些矩陣(注意:你不能旋轉或者翻轉它們),但是每兩個矩陣應該恰好對應。即第一列對第一列(或是第一行對第一行)比如說:
聰明的你一定可以找到一種排列方法使“連續1的序列最長”。我們定義“連續的1序列”為這個序列僅含1且這個序列不拐彎,它可以是橫著或者豎著的。請輸出最長的“連續的1序列”長度
輸入描述:


第一行一個n。
接下來 4*n行,每行4個數。(僅含0,1)。代表n個0/1矩陣。
輸出描述:
一個數字表示最長的“連續的1序列”的長度。
示例1
輸入
1
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
輸出
4
示例2
輸入
1
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
輸出
0
示例3
輸入
3
1 0 1 0
0 0 1 0
1 0 1 0
0 1 0 1

1 0 1 0
0 1 1 1
1 0 1 1
1 1 1 0

1 0 1 1
0 1 0 0
0 1 0 0
0 0 0 1
輸出
7
備註:
對於前30%,保證n<=1e3.( 然而並沒卵用 )
對於前100%的資料,保證n<=1e5.
亂搞是沒有活路的,出題人在驗題時已經卡掉9種奇奇怪怪的dp和貪心了。
包括但不限於區間dp,O(n)的錯誤dp,模擬退火演算法,爬山演算法,遺傳演算法等.
而且出題人特別卡掉了快讀。
ps:10%的資料保證隨機。

 

題解:

對四行四列分別統計,每一行(列)下的每一個矩陣都有三種情況:

  1、四個 $1$ 全滿;這個直接計數為 $fullcnt$。

  2、不是四個 $1$,但是左起(上起)或者右起(下起)能至少有一個 $1$;左起(上起)的放一起統計,右起(下起)的放一起統計。

  3、兩側都是 $0$,那麼此時只有中間一個或者兩個 $1$,這個再單獨統計。

那麼,對於某一行(某一列),他能產生的最長連續 $1$ 的長度為:

  1、四個 $1$ 全滿的計數 $fullcnt$ 產生貢獻 $4 \times fullcnt$。

  2、左起(上起)中最長的,加上,右起(下起)中最長的,即產生的貢獻(當然,如果兩個最長的同屬於一個矩陣,則要考慮在“左起最長+右起次長”和“右起最長+左起次長”中挑一個)。

  3、兩側都是 $0$,顯然上面兩種情況的貢獻就均為 $0$,而本情況能產生 $2$ 或 $3$ 的貢獻。

 

AC程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;

int n;
struct Mat
{
    int mp[5][5];
    int cnt[2][5][2];
    void input()
    {
        for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%d",&mp[i][j]);
        for(int i=1;i<=4;i++)
        {
            cnt[0][i][0]=0;
            for(int j=1;j<=4;j++)
            {
                if(mp[i][j]) cnt[0][i][0]++;
                else break;
            }//printf("第%d行左邊起%d\n",i,cnt[0][i][0]);
            cnt[0][i][1]=0;
            for(int j=4;j>=1;j--)
            {
                if(mp[i][j]) cnt[0][i][1]++;
                else break;
            }//printf("第%d行右邊起%d\n",i,cnt[0][i][1]);
        }
        for(int j=1;j<=4;j++)
        {
            cnt[1][j][0]=0;
            for(int i=1;i<=4;i++)
            {
                if(mp[i][j]) cnt[1][j][0]++;
                else break;
            }//printf("第%d列上邊起%d\n",j,cnt[1][j][0]);
            cnt[1][j][1]=0;
            for(int i=4;i>=1;i--)
            {
                if(mp[i][j]) cnt[1][j][1]++;
                else break;
            }//printf("第%d列下邊起%d\n",j,cnt[1][j][1]);
        }
    }
}mat[maxn];

struct Node
{
    int val;
    int id;
    bool operator<(const Node& oth)const{return val>oth.val;}
    Node(int _val,int _id){val=_val;id=_id;}
};
vector<Node> v[2][5][2],u[2][5];
int fullcnt[2][5]={0};

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        mat[i].input();
        for(int rc=0;rc<=1;rc++)
        {
            for(int k=1;k<=4;k++)
            {
                if(mat[i].cnt[rc][k][0]==4 || mat[i].cnt[rc][k][1]==4) //全滿,type=2
                    fullcnt[rc][k]++;
                else if(mat[i].cnt[rc][k][0]>0) //左側或上側,type=3
                    v[rc][k][0].push_back(Node(mat[i].cnt[rc][k][0],i));
                else if(mat[i].cnt[rc][k][1]>0) //右側或下側,type=1
                    v[rc][k][1].push_back(Node(mat[i].cnt[rc][k][1],i));
                else //只存在於內部,type=4
                {
                    int num=(!rc)?(mat[i].mp[k][2]+mat[i].mp[k][3]):(mat[i].mp[2][k]+mat[i].mp[3][k]);
                    u[rc][k].push_back(Node(num,i));
                }
            }
        }
    }
    int ans=0;
    for(int rc=0;rc<=1;rc++)
    {
        for(int k=1;k<=4;k++)
        {
            sort(v[rc][k][0].begin(),v[rc][k][0].end());
            sort(v[rc][k][1].begin(),v[rc][k][1].end());
            int res;
            if(v[rc][k][0].size() && v[rc][k][1].size())
            {
                Node& m1=v[rc][k][0][0],m2=v[rc][k][0][1];
                Node& n1=v[rc][k][1][0],n2=v[rc][k][1][1];
                res=(m1.id!=n1.id)?(m1.val+n1.val):max(m1.val+n2.val,m2.val+n1.val);
            }
            else if(v[rc][k][0].size() || v[rc][k][1].size())
            {
                if(v[rc][k][0].size()) res=v[rc][k][0][0].val;
                else res=v[rc][k][1][0].val;
            }
            else
            {
                if(u[rc][k].size())
                {
                    sort(u[rc][k].begin(),u[rc][k].end());
                    res=u[rc][k][0].val;
                }
                else res=0;
            }
            ans=max(ans,4*fullcnt[rc][k]+res);
        }
    }
    cout<<ans<<endl;
}

 

給一些測試資料:

1
0 0 0 0
0 1 1 0
0 1 0 0
0 0 0 0
1
0 0 0 0
0 1 0 0
0 1 0 0
0 0 0 0
1
0 0 0 0
0 1 0 0
0 0 1 0
0 0 0 0
1
1 1 1 0
0 0 0 0
0 1 1 1
1 0 0 0
1
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 1 1 0
0 0 0 0