Wannafly挑战赛20 A 染色 B 背包

A 染色
当时看了一下题目,觉得还挺简单的,想了一下思路,大概15分钟A了
思路大概是这样的:反正要变成的颜色肯定是树上某个点的颜色,我们枚举树上所有的点变成某个点颜色的代价,取其中的最小值即可,可以线性得到,因为树上所有的点变成某个点node颜色的代价为 =树上所有点的价值-不需要改变颜色点的价值和+需要改变颜色点的数量*点node的价值
这些价值相同的数量,我是用map存的

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=100000+100;

ll ans[maxn];

int main(){

    map<ll,int>M;
    map<ll,int>cnt;
    int n;
    scanf("%d",&n);
    ll sum=0;
    for(int i=1;i<=n;i++) scanf("%lld",&ans[i]),sum+=ans[i],cnt[ans[i]]++;
    int u,v;
    for(int i=1;i<n;i++) scanf("%d%d",&u,&v);
    ll Min=1e18;
    for(int i=1;i<=n;i++){

        if(M[ans[i]]) continue; //当然可以不要,不影响结果,习惯加上
        M[ans[i]]=1;
        ll tmp=sum-(ll)cnt[ans[i]]*ans[i]+(ll)(n-cnt[ans[i]])*ans[i];
        Min=min(Min,tmp);
    }
    printf("%lld\n",Min);
}

B 背包
晚上比赛的时候也是用的相同的方法,但是没有考虑到m是偶数的特殊情况,导致只过了90%的数据
思路大概是这样的:
结构体存储物品
结构体按物品的价值从小到大排序

1.当m是奇数时,这个就好办了,我们把要取的数分成三段取,即前中后, 个数分别为(m-1)/2 ,1 , (m-1)/2,比如取7个数, 前取 3 ,中取1 ,后取 3
所有我们可以枚举中间这个数,但是首先要把中间这个数的前面和后面的(m-1)/2个最小容量值预处理出来,可以用优先队列进行处理,具体看代码。


2.当m是偶数时,要麻烦一点,我们还是把要取的数分成三段取,即前中后, 个数分别为(m-1)/2 ,1 , (m-1)/2+1,比如取8个数, 前取 3 ,中取1 ,后取 4
我们依然枚举中间这个数,因为此时平均值=(中间这个数+后面取的第一个数)/2,所以后面取(m-1)/2+1个数的时候,第一个数越往后面取平均值就越大(当然要符合情况的条件下),这里可以二分得到,仔细想一想为什么可以二分。
取后面的数为什么可以二分:假设在区间 [l,n]中取 (m-1)/2+1个数符合情况,那在区间 [l-1,n]中取(m-1)/2+1个数肯定符合情况,因为还多了一个数,所以当 [l,n] 满足情况,我们就不需要管 l 前面的数了,因为不会有更大的平均值,所以我们考虑 l 后面的数即可,这就符合二分的性质了

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=100000+100;

priority_queue<ll,vector<ll>,less<ll> >lque,rque;
ll l[maxn],r[maxn];
struct Node{

    ll v,c;
}node[maxn];
ll v;
int n,m;
int l_num,r_num;

inline bool cmp(Node a,Node b){

    return a.v<b.v;
}

void slove(){

    l_num=r_num=(m-1)/2;
    ll sum=0;
    for(int i=1;i<=l_num;i++) sum+=node[i].c,lque.push(node[i].c);
    l[l_num]=sum;
    for(int i=l_num+1;i<=n;i++){

        if(lque.empty()) continue;
        ll tmp=lque.top();
        if(tmp>node[i].c){

            sum-=tmp;
            sum+=node[i].c;
            lque.pop();
            lque.push(node[i].c);
        }   
        l[i]=sum;
    }

    if(m%2==0) r_num++;
    sum=0;
    for(int i=n;i>n-r_num;i--) sum+=node[i].c,rque.push(node[i].c);
    r[n-r_num+1]=sum;
    for(int i=n-r_num;i>=1;i--){

        ll tmp=rque.top();
        if(tmp>node[i].c){

            sum-=tmp;
            sum+=node[i].c;
            rque.pop();
            rque.push(node[i].c);
        }
        r[i]=sum;
    }
}

int main(){

    scanf("%lld%d%d",&v,&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&node[i].v,&node[i].c);
    sort(node+1,node+n+1,cmp);

    slove();
    if(m%2){

        ll Max=0;
        for(int i=n-r_num;i>l_num;i--){

            if(r[i+1]+l[i-1]+node[i].c<=v){

                Max=node[i].v;
                break;
            }
        }
        printf("%lld\n",Max);
    }
    else{

        ll Max=0;
        for(int i=n-r_num;i>l_num;i--){

            int L=i+1;
            int R=n-r_num+1;
            int key=-1;
            while(L<=R){

                int mid=(L+R)>>1;
                if(r[mid]+l[i-1]+node[i].c<=v) L=mid+1,key=mid;
                else R=mid-1;
            }
            if(key==-1) continue;
            Max=max(Max,(node[i].v+node[key].v)/2);
        }
        printf("%lld\n",Max);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/81141212