1. 树中删边
多多有一颗 n 个节点的树,树中每一条边都有一个权值。
多多还有一个长度为 n 的正整数序列:删除树中若干条边之后(或者不删),就会变成一个有 x 个连通块的图,
此时的得分为:剩余边权和 + ((两个可以互相到达的节点属于同一个连通块,注意一个孤点也是一个连通块)
多多可以删除图中若干条边(可以不删)。现在多多想知道,最多能够得到多少分。现在请你告诉多多答案
贪心
int main() {
int n;
cin>>n;
int s = 0;
vector<int> v(n);
vector<int> a(n);
for(int i=0;i<n;i++)
cin>>v[i];
for(int i=1;i<n;i++){
int from,to;
cin>>from>>to>>a[i];
s+=a[i];
}
int res = 0;
sort(a.begin()+1,a.end());
for(int i=0;i<n;i++){
s-=a[i];
res = max(res,s+v[i]);
}
cout<<res<<endl;
return 0;
}
2. 数列操作
多多有一列正整数组成的数列,支持两种操作:选取一个偶数,使其值减半选取两个数字,
移除并替换为两个数字的和多多希望最终能够得到一个全为奇数的数列,请计算最少需要操作几次
思维题
int main() {
int n;
cin>>n;
vector<int> nums(n);
for(int i=0;i<n;i++)
cin>>nums[i];
int res = INT_MAX;
int odd = 0;//记录奇数个数
//偶数通过n次减半最终可以变为奇数,也就是其第一个1在二进制第几位,表示要操作几次,奇数可以将偶数变成奇数
for(auto num:nums){
int cnt = 0;
int cur = num;
while(cur%2==0){
cnt++;
cur/=2;
}
if(cnt==0) odd++;
res = min(res,cnt);
}
if(odd==0) cout<<n-1+res<<endl;
else cout<<n-odd<<endl;
}
3. 交换礼物
多多携带一件价值为的礼物参加了一个节日派对。除多多外在场的有个人,第i个人的当前持有的礼物价值为。
多多可以和任意当前持有礼物价值比多多低的人交换礼物。请问最少经过多少次交换,可以使得个人持有的礼物价值形成单调不减的数列
思维题
int main() {
int n,v;
cin>>n>>v;
vector<int> nums(n);
for(int i=0;i<n;i++)
cin>>nums[i];
int idx = 1;
while(idx<n){
if(nums[idx]<nums[idx-1]) break;
idx++;
}
if(idx==n){
cout<<0<<endl;
return 0;
}
nums[idx] = v;
vector<int> temp = nums;
sort(temp.begin(),temp.end());
int res = 0;
for(int i=n-1;i>=0;i--){
if(nums[i]==temp[i]) continue;
if(v==temp[i]){
res++;
v = nums[i];//替换
}
else{
cout<<-1<<endl;
return 0;
}
}
cout<<res<<endl;
return 0;
}
4. 字符串操作
给定长度为n的01串,定义一次操作为, 将整个字符串按顺序分为两部分, 将两部分各自翻转后再按原顺序拼接。
提问,进行任意次的操作后,可以得到的最长的连续的01交替的子串有多长。
例:原01串为 01001,可以先将原串分为 010 和 01 两部分, 分别翻转得到 010 和 10 ,
按原顺序拼接后得到 01010. 此时最长的连续交替子串为 01010,长度为5.
思维题
int main() {
int n;
cin>>n;
string str;
cin>>str;
int res = 1; int cnt = 1;
for(int i=1;i<2*n;i++)
if(str[i%n]!=str[(i-1)%n]){
cnt ++;
res = max(res,cnt);
}
else cnt = 1;
cout<<min(res,n)<<endl;
return 0;
}