2019牛客暑期多校第二場

F、https://ac.nowcoder.com/acm/contest/882/F

題意:有2N個人,分成兩組,每組N個。使得不同組間的人的競賽值之和最大。

解法之一:暴搜!!。時限4S,感覺就是明顯暗示這是要暴力搜的題。(再次溫習DFS)(枚舉長度為N的子集,保存結果的最大)。

#include <bits/stdc++.h>
using  namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
int N;
ll a[50][50];
ll res=-1;
ll v1[50],v2[50];
void dfs(ll sum,int x,int cnt1,int cnt2)
{
    if(cnt1==N){
        ll tmp=sum;
        for(int i=x;i<=2*N;i++){
            for(int j=1;j<=cnt1;j++){
                tmp+=a[i][v1[j]];
            }
        }
        res=max(res,tmp);
        return ;
    }
    if(cnt2==N){
        ll tmp=sum;
        for(int i=x;i<=2*N;i++){
            for(int j=1;j<=cnt2;j++){
                tmp+=a[i][v2[j]];
            }
        }
        res=max(res,tmp);
        return ;
    }
    ll tmp=sum;
    v1[++cnt1]=x;
    for(int i=1;i<=cnt2;i++){
        tmp+=a[v2[i]][x];
    }
    dfs(tmp,x+1,cnt1,cnt2);
    cnt1--;

    tmp=sum;
    v2[++cnt2]=x;
    for(int i=1;i<=cnt1;i++){
        tmp+=a[v1[i]][x];
    }
    dfs(tmp,x+1,cnt1,cnt2);
    cnt2--;
}

int main()
{
    scanf("%d",&N);
    for(int i=1;i<=2*N;i++){
        for(int j=1;j<=2*N;j++){
            scanf("%lld",&a[i][j]);
        }
    }
    dfs(0,1,0,0);
    printf("%lld\n",res);
    return 0;
}

H、https://ac.nowcoder.com/acm/contest/882/H

題意:給一個大小為N*M的01矩陣,求這個矩陣裏的第二大01矩陣(全1)。

解法之一:在求最大01矩陣的做法的基礎上修改,求最大的做法是:先每個1都預處理這個點所能到達向上的最大高度,再用單調棧維護每個1所能到達的最左最右的點的坐標。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
char mp[2010][2010];
int pre[2010][2010];
int l[2010],r[2010];
stack<int>s;
int main()
{
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",mp[i]+1);
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j]=='0')
                pre[i][j]=0;
                else
                pre[i][j]=pre[i-1][j]+1;
            }
        }
        int max1=-1;
        int max2=-1;
        int fl,fr,fi;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                while(!s.empty()&&pre[i][j]<=pre[i][s.top()]) s.pop();
                l[j]=s.size()==0?1:s.top()+1;
                s.push(j);
            }
            while(!s.empty()) s.pop();
            for(int j=m;j>=1;j--)
            {
                while(!s.empty()&&pre[i][j]<=pre[i][s.top()])
                s.pop();
                r[j]=s.size()==0?m:s.top()-1;
                s.push(j);
            }
            while(!s.empty()) s.pop();
            for(int j=1;j<=m;j++)
            {
                int now=pre[i][j]*(r[j]-l[j]+1);
                if(now>max1){
                    max1=now;
                    fl=l[j],fr=r[j],fi=i;
                }
            }
        }
        int ppp=fr-fl+1;
        int yyy=max1/ppp;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                while(!s.empty()&&pre[i][j]<=pre[i][s.top()]) s.pop();
                l[j]=s.size()==0?1:s.top()+1;
                s.push(j);
            }
            while(!s.empty()) s.pop();
            for(int j=m;j>=1;j--)
            {
                while(!s.empty()&&pre[i][j]<=pre[i][s.top()])
                s.pop();
                r[j]=s.size()==0?m:s.top()-1;
                s.push(j);
            }
            while(!s.empty()) s.pop();
            for(int j=1;j<=m;j++)
            {
                if(r[j]==fr&&l[j]==fl&&i==fi) continue;
                int now=pre[i][j]*(r[j]-l[j]+1);
                if(now>max2){
                    max2=now;
                }
            }
        }
        int temp=max1-min(ppp,yyy);
        if(max2<temp) cout<<temp<<endl;
        else cout<<max2<<endl;
        return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值