A
对于n本书拿出k本较为难实现,但是从n本书里拿出n-k本就容易多了
对于n本书里拿一本为特殊情况,不管怎么拿都为0
对于n本书里拿n-k本的话,我们假设拿的最后一本为i那么
他就是拿出n-k-1本书的情况再加上拿出第i本的情况
其中差值变化为拿出n-k-1本书的值,加上我abs(w[i]-w[j])(j为拿出n-k-1本书情况的最后面的那本书)
将f[i][j]视为从i本书里拿出j本的最小差值
于是可以得到转移方程f[i][j] = min(f[i][j],f[l][j]+abs(w[i]-w[j]))
其中l为拿出j-1到i-1本书的情况
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;struct sss{int l, r;
}w[110];
int n, k, f[110][110];
bool cmp(sss w1, sss w2){return w1.l<w2.l;
}
void solve(){cin >> n >> k;k = n-k;for(int i = 1; i <= n; i++) cin >> w[i].l >> w[i].r;for(int i = 1; i <= n; i++)for(int j = 1;j <= n; j++)f[i][j] = 1e18;sort(w+1,w+1+n,cmp);for(int i = 1; i <= n; i++) f[i][1] = 0;for(int i = 2; i <= n; i++){for(int j = 2; j <= min(i,k); j++)for(int l = j-1; l < i; l++)f[i][j]=min(f[i][j],f[l][j-1]+abs(w[i].r-w[l].r));}int mins = 1e18;for(int i = k; i<=n; i++){mins = min(mins, f[i][k]);}cout << mins;
}
signed main (){ios::sync_with_stdio(false);cin.tie(nullptr); int T = 1;
// cin >> T;while (T--) {solve();}return 0;
}
B
找出最大的两个值,与最大值相等就输出第二大的值,否则输出第一大的值
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;int n, a[200010], b[200010];
void solve(){cin >> n;for(int i = 1; i <= n; i++){cin >> a[i];b[i] = a[i];}sort(b+1,b+1+n);for(int i = 1; i <= n; i++){if(a[i] == b[n]) cout << b[n-1] << endl;else cout << b[n] <<endl;}
}
signed main (){ios::sync_with_stdio(false);cin.tie(nullptr); int T = 1;
// cin >> T;while (T--) {solve();}return 0;
}
C
考虑拿两种技能都能有的情况的值,第一个技能的最小花费和第二个技能的最小花费的值的和,输出他们的最小值即可。
#define endl "\n"
#define int long long
using namespace std;int n;
struct aaa{int num;string ch;
}w[200010];
bool cmp(aaa w1, aaa w2){if(w1.ch!=w2.ch){return w1.ch>w2.ch;}return w1.num<w2.num;
}
void solve(){cin >> n;for(int i = 1; i <= n; i++){cin >> w[i].num >> w[i].ch;}sort(w+1,w+1+n,cmp);int mins = 1e18;int j;for(j = 1; j <= n; j++){if(w[j].ch=="11"){mins = min(mins, w[j].num);}else break;}int ret = 1e18, p = 0;for(; j <= n; j++){if(w[j].ch=="10"){ret = min(ret, w[j].num);p = 1;}else break;}for(; j <= n; j++){if(w[j].ch == "01"){ret+=w[j].num;p = 2;break;}else break;}if(p==2)mins = min(mins, ret);if(mins == 1e18) cout << "-1" << endl;else cout << mins << endl;
}
signed main (){ios::sync_with_stdio(false);cin.tie(nullptr); int T = 1;cin >> T;while (T--) {solve();}return 0;
}```
#D
![](https://img2024.cnblogs.com/blog/3534879/202412/3534879-20241201163812206-576503710.png)
要求不重复的正整数,那就从1开始给,直到n值不允许再额外给出比他大1的值时,直接给出剩下的全部
```#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;int n, a[1100];
void solve(){cin >> n;int num = 0;for(int i = 1; i <= n; i++){if(n>=i+i+1){a[i] = i;num++;n-=i;}else{a[i] = n;num++;break;}}cout << num << endl;for(int i = 1; i <= num; i++){cout << a[i];if(i!=num) cout << ' ';}
}
signed main (){ios::sync_with_stdio(false);cin.tie(nullptr); int T = 1;
// cin >> T;while (T--) {solve();}return 0;
}```
#E
![](https://img2024.cnblogs.com/blog/3534879/202412/3534879-20241201163841557-1929111736.png)
根据题意可以得到f(i)<=g(i)是一定成立的,因为比他大的数的数量加一 跟 比他大的数的数量加上自身是一样大的,若再加上其他与自身相等的数就是大于的情况了
那剩下需要考虑的就只有k的情况
那么对于ai刚好等于ak的情况,我们就不需要操作。
对于ai大于ak的情况,即k可能大于g(i)的情况,就需要把比他小的值到ak的值全部变为自身即可。(此处需要前缀和来维护)
对于ai小于ak的情况,即k可能小于f(i)的情况,就需要把ai变成ak即可
```#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;struct sss{int num;int p;
}w[500010];
int n, k;
bool cmp(sss w1, sss w2){return w1.num>w2.num;
}
int sum[500010], ret[500010];
void solve(){int xxxx;cin >> xxxx >> n >> k;for(int i = 1; i <= n; i++){cin >> w[i].num;w[i].p = i;}sort(w+1,w+1+n, cmp);for(int i = 1; i <= n; i++) sum[i] = sum[i-1]+w[i].num;for(int i = 1; i <= n; i++){if(w[i].num == w[k].num) ret[w[i].p] = 0;else if(w[i].num > w[k].num){ret[w[i].p] = w[i].num*(k-i)-sum[k]+sum[i];
// cout << w[i].num << ' ' << k << ' ' << i << ' ' << sum[k] << ' ' << sum[i] << endl;}else if(w[i].num < w[k].num) ret[w[i].p] = w[k].num-w[i].num;}for(int i = 1; i <= n; i++){cout << ret[i] << endl;}
}
signed main (){ios::sync_with_stdio(false);cin.tie(nullptr); int T = 1;
// cin >> T;while (T--) {solve();}return 0;
}```