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);
}
}