C
- 题意: n场比赛,总共p分,w为胜利一场的得分,d为平局的得分,求胜利,平局,失败的场数
- 思路: 因为d次胜利与w次平局所得的分是一样的,假如平局次数超过w次则可以将其转换成d次胜利(w>d所以一定可以转化),枚举到1e5就行了...
D
- 题意: 树上染色,共有三种颜色且所有相邻三个点颜色不能重复,每个点染不同颜色有不同的值,求最小值且合法的染色方案
- 思路: 首先树必须是条链,然后枚举前三个点的全排列就可以确定后面点的颜色,求最小值即可(写了个dp调了我半小时QAQ).
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5+10;
int n;
vector<int> cost[3];
vector<vector<int> > adj;
vector<int> p,perm ={0,1,2},best_perm,ans;
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int u,v,root;
cin >> n;
for(int i=0;i<3;++i){
cost[i].resize(n);
for(int j=0;j<n;++j) cin >> cost[i][j];
}
adj.assign(n,{});
for(int i=0;i<n-1;++i){
cin >> u >> v;
u--; v--;
adj[u].push_back(v);
adj[v].push_back(u);
}
for(int i=0;i<n;++i){
if(adj[i].size()>2){
cout <<"-1
";
return 0;
}else if(adj[i].size()==1){
root = i;
}
}
p.push_back(root);
while(p.size()<n){
v = p.back();
for(auto nx:adj[v]){
if(p.size()==1 || nx != p[p.size()-2]){
p.push_back(nx);
break;
}
}
}
ll best = 1LL<<62;
do{
ll score = 0;
for(int i=0;i<n;++i) score += cost[perm[i%3]][p[i]];
if(score<best){
best_perm = perm;
best = score;
}
}while(next_permutation(perm.begin(),perm.end()));
cout << best << '
';
ans.resize(n);
for(int i=0;i<n;++i) ans[p[i]] = best_perm[i%3];
for(int i=0;i<n;++i) cout << ans[i]+1<<' ';
cout <<'
';
return 0;
}
E
- 题意: 一个序列,每次可以选一个数+1或-1,可以操作k次,求最小化最大减最小的差.
- 思路: 二分差,肯定有一个a[i]是不变的,check时就枚举a[i]不变(上界下界枚举两次),然后lower_bound找到比下界小的,要加到下界,upper_bound找到比上界大的,要减到上界,算操作次数是否满足小于k.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5+10;
ll n,k;
ll a[N],sum[N];
bool check(int d){
for(int i=1;i<=n;++i){
int low = lower_bound(a+1,a+1+n,a[i])-a-1;
int hgh = upper_bound(a+1,a+1+n,a[i]+d)-a;
ll tot = 1LL*low*a[i] - sum[low] + sum[n] - sum[hgh-1] - 1LL*(n-hgh+1)*(a[i]+d);
if(tot <=k) return true;
}
for(int i=1;i<=n;++i){
int hgh = upper_bound(a+1,a+1+n,a[i])-a;
int low = lower_bound(a+1,a+1+n,a[i]-d)-a-1;
ll tot = 1LL*low*(a[i]-d) - sum[low] + sum[n] - sum[hgh-1] - 1LL*(n-hgh+1)*a[i];
if(tot <=k) return true;
}
return false;
}
int main(){
cin >> n >> k;
for(int i=1;i<=n;++i) cin >> a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;++i) sum[i] = sum[i-1] + a[i];
int l = 0,r = 1e9;
int mid,ans = -1;
while(l<=r){
mid = (l+r)>>1;
if(check(mid)){
ans = mid;
r = mid-1;
}else{
l = mid+1;
}
}
cout << ans << endl;
return 0;
}
这几天训练莫得动力,再不加大力度自己要莫得了