2019牛客暑假多校训练营(第二场)

D:https://ac.nowcoder.com/acm/contest/882/D

给出n,k,n个数,求第k小团。用bitset。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef bitset<105> b;
ll a[105];
b bb[105];
struct node
{
    ll v;
    b w;
    bool operator <(const node &a)const{
        return a.v<v;
    }
};
priority_queue<node> q;
int main()
{
    ll n,k;
    scanf("%lld%lld",&n,&k);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    char str[105];
    for(ll i=1;i<=n;i++){
        scanf("%s",str+1);
        for(ll j=1;j<=n;j++){
            if(str[j]=='1'){
                bb[i].set(j);
            }
        }
    }
    node e;
    e.v=0;
    e.w.reset();//重置
    q.push(e);
    ll cnt=0;
    while(cnt<k){
        if(q.empty()){
            printf("-1\n");
            return 0;
        }
        if(cnt==k-1){
            printf("%lld\n",q.top().v);
            return 0;
        }
        node f=q.top();
        ll val=f.v;
        b bit=f.w;
        q.pop();
        ll pos=1;
        for(ll i=1;i<=n;i++){
            if(bit[i]){
                pos=i+1;
            }
        }
        //记录每次最后一位是1的位置
        for(ll i=pos;i<=n;i++){
            //是0并且能加进去
            if(bit[i]==0&&((bit&bb[i])==bit)){
                node ff;
                b g=bit;
                g.set(i);//把这位置1
                ff.w=g;
                ff.v=val+a[i];//加上这一位
                q.push(ff);
            }
        }
        cnt++;
    }
    return 0;
}

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

给出2n个人,及每两人之间的竞争力。把这两人分成两组,同一组间竞争力为0,最大化一个人和另一队所有人的竞争力

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[30][30],s[30],n,mx=0,ans=0;
vector<ll> v;
void dfs(ll num)
{
    //选够n个
    if(v.size()==n){
        mx=max(mx,ans);
        return ;
    }
    //所选的超过2*n个
    if(num==2*n+1){
        return ;
    }

    //把num加进去该队的影响,和所有人的和
    ll f=s[num];
    //减去和它成为一队的
    for(int i=0;i<v.size();i++){
        f-=a[num][v[i]]*2;
    }
    ans+=f;
    v.push_back(num);
    dfs(num+1);

    ans-=f;
    v.pop_back();
    dfs(num+1);
}
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=2*n;i++){
        for(ll j=1;j<=2*n;j++){
            scanf("%lld",&a[i][j]);
            s[i]+=a[i][j];
        }
    }
    dfs(1);
    printf("%lld\n",mx);
    return 0;
}

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

求第二大的矩阵,全是1.

这个有模板,悬线法,找到每个点最左端到哪儿,最右端到哪儿,还有上端到哪儿。

还有一种做法,取每个位置的高度,宽度初始为1,在高度存在的情况下,不断向左扩展,逐个更新计算。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
char s[maxn];
int dp[maxn][maxn],st[maxn],n,m;
int mx=0,mxx=0,top;
void add(int x,int y)
{
    int area=x*y;
    if(area>=mx){
        mxx=mx;
        mx=area;
    }
    else if(area>mxx){
        mxx=area;
    }
}
int main()
{
    memset(dp,0,sizeof(dp));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",&s);
        for(int j=1;j<=m;j++){
            if(s[j-1]=='1')  dp[i][j]=1;
            dp[i][j]+=dp[i-1][j]*dp[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int len=dp[i][j],dep=1;
            while(len){
                add(dep,len);
                len=min(len,dp[i][j-dep]);
                dep++;
            }
        }
    }
    printf("%d\n",mxx);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值