A - Glutton Takahashi
题意:
给你了N盘菜, 当你连续吃两盘甜的菜就死了,问能不能吃完所有的菜。当中间出现连续的两盘甜菜不行,最后两个位置可以出现连续的甜菜。
void solve(){
int n;
cin >> n;
vector<string > v;
string s;
for(int i = 1; i <= n; i++){
cin >> s;
v.push_back(s);
}
for(int i = 0; i < n - 2; i++){
if(v[i] == "sweet" && v[i + 1] == "sweet"){
cout <<"No" << endl;
return ;
}
}
cout <<"Yes" << endl;
}
B - Grid Walk
题意
给你一张有边界的地图,地图中有若干障碍物,人物不能穿过障碍物和边界。给你人物的起始位置,和一个指令集,问经过这些指令后人物的位置。因为指令集不大,直接模拟即可。
void solve(){
cin >> n >> m;
cin >> sx >> sy;
for(int i = 0; i <= n + 1; i++){
for(int j = 0; j <= m + 1; j++){
a[i][j] = '#';
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> a[i][j];
}
}
string s;
cin >> s;
int x = sx, y = sy;
for(int i = 0; i < s.size(); i++){
if(s[i] == 'L'){
if(a[x][y - 1] != '#') y = y - 1;
}else if(s[i] == 'R'){
if(a[x][y + 1] != '#') y = y + 1;
}else if(s[i] == 'U'){
if(a[x - 1][y] != '#') x = x - 1;
}else{
if(a[x + 1][y] != '#') x = x + 1;
}
}
cout << x <<" " << y << endl;
}
C - Minimum Glutton
题意
你有N盘菜肴,每盘菜肴有甜度和咸度两个属性。你可以将菜肴任意排序,按顺序吃掉,当甜度超过X或当咸度超过Y时,你死了。问:最少吃几盘菜。由于是最少吃几盘,最后不是被甜死就是咸死,按甜度和咸度排序,甜死的最小和咸死的最小取min即可。
void solve(){
cin >> n >> X >> Y;
for(int i = 1; i <= n; i++){
cin >> a[i].first;
}
for(int i = 1; i <= n; i++){
cin >> a[i].second;
}
int ans = n;
sort(a + 1, a + 1 + n, cmp1);
int sum1 = 0, sum2 = 0;
int i = 0;
while(i < n && sum1 <= X && sum2 <= Y) {
i++;
sum1 += a[i].first;
sum2 += a[i].second;
}
ans = min(ans, i);
i = 0, sum1 = 0, sum2 = 0;
sort(a + 1, a + 1 + n, cmp2);
while(i < n && sum1 <= X && sum2 <= Y) {
i++;
sum1 += a[i].first;
sum2 += a[i].second;
}
ans = min(ans, i);
cout << ans << endl;
}
D - K-th Nearest
题意
在一个数轴上已有N个点,接下来你要处理Q次询问。每次询问会给你一个点B,问距离这个点第K近的点距离它的距离。这题我们需要二分答案,假设答案为D,则[x - D, x + D]这个区间内必有>=K个点,距离变大,区间变大,区间内的点数不会变少,这样具有单调性的问题,可以使用二分去做。如何去计算[x - D, x + D] 这个区间内有多少点呢,我们依旧可以二分,找到第一个>= x - D
的下标p1和最后一个<= x + D的下标p2,点的个数即为p2 - p1 + 1了。
const int N = 1e5+5;
int a[N], n, q;
int Search1(int x){
int l = 1, r = n;
int ans = -1;
while(l <= r){
int mid = (l + r) >> 1;
if(a[mid] <= x) {
ans = mid;
l = mid + 1;
}else r = mid - 1;
}
return ans;
}
int Search2(int x){
int l = 1, r = n;
int ans = -1;
while(l <= r){
int mid = (l + r) >> 1;
if(a[mid] >= x) {
ans = mid;
r = mid - 1;
}else l = mid + 1;
}
return ans;
}
bool check(int b, int k, int d){
int pos1 = Search1(b + d);
int pos2 = Search2(b - d);
if(pos1 == -1 || pos2 == -1) return 0;
return (pos1 - pos2 + 1) >= k;
}
void solve(){
cin >> n >> q;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
int b, k;
while(q--){
cin >> b >> k;
int l = 0, r = 2e9;
int ans = 0;
while(l <= r){
int mid = (l + r) / 2;
if(check(b, k, mid)){
ans = mid;
r = mid - 1;
}else l = mid + 1;
}
cout << ans << endl;
}
}
E - Maximum Glutton
题意
问题和C题基本相同,不过现在求的是最多能吃几盘菜。这个题目给我的第一感觉是二维费用背包问题,求一个重量不超过X且体积不超过Y的背包最多能装多少物品。这个我们的dp设计为dp[i][j][k],考虑前i个物品,重量为j且体积为k的背包能装的最大物品数。时间复杂度为O(N * X * Y),由于X和Y都为1e4,显然是不可行的。由于N很小,考虑这个dp,dp[i][j][k]表示考虑前i个物品,恰好选择k个物品,甜度为k的最小咸度。这样时间复杂度为O(N * N * X) 。
const int N = 85;
const int M = 1e4+5;
typedef pair<int, int> PII;
PII a[N];
int n, X, Y;
int f[N][N][M];
void solve(){
cin >> n >> X >> Y;
for(int i = 1; i <= n; i++){
cin >> a[i].first >> a[i].second;
}
memset(f, 0x3f, sizeof(f));
f[0][0][0] = 0;
for(int i = 1; i <= n; i++){
f[i][0][0] = 0;
for(int j = 1; j <= i; j++){
for(int k = 0; k <= X; k++){
f[i][j][k] = f[i - 1][j][k];
if(k >= a[i].first) f[i][j][k] = min(f[i][j][k], f[i - 1][j - 1][k - a[i].first] + a[i].second);
}
}
}
int ans = 0;
for(int i = 0; i <= n; i++){
for(int j = 1; j <= X; j++){
if(f[n][i][j] <= Y) ans = max(ans, i);
}
}
ans = min(ans + 1, n);
cout << ans << endl;
}
F - Range Connect MST
题意
给你一张有N + Q个点的图,有Q次操作,每次操作给你三个数,L,R,W。在第i次操作,我们会将Li-Ri的点与编号为N + i点连接起来。问:这个图是否连通,如果连通请输出这个图的最小生成树的值。根据最小生成树的Kruskal算法,我们总是先连接最小的边。我们先将操作按W的值进行升序排序,我们发现由于每次操作N + i 这个点总是不连通,即每个操作至少加一条边,且Li与N + i总是不连通。我们将Li与N + i连接后,与Li已连接的点都不需要与N+i进行连边了,我们可以跳过这些点,由于操作是连续的,与Li已连接的点也应该是连续的,所以我们跳过的点是一个区间。我们使用并查集来维护这些区间,每当我们与当前点建边后将这个点与加入Li的集合中,且跳到我们维护的这个点的右端点即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define ios ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define int long long
const int N = 2e5+5;
int ans[N];
int fa[N], fr[N];
struct node{
int l, r, idx, w;
bool operator < (const node &obj){
return this->w < obj.w;
}
};
int Find(int x){
return fa[x] == x ? fa[x] : fa[x] = Find(fa[x]);
}
void init(){
for(int i = 0; i < N; i++){
fa[i] = i;
fr[i] = i;
}
}
void join(int a, int b){
int aa = Find(a), bb = Find(b);
if(aa != bb){
fa[aa] = bb;
fr[aa] = fr[bb] = max(fr[aa], fr[bb]);
}
}
vector<node> e;
int n, q;
void solve(){
cin >> n >> q;
int l, r, w;
init();
for(int i = 1; i <= q; i++){
cin >> l >> r >> w;
e.push_back({l, r, i, w});
}
sort(e.begin(), e.end());
LL ans = 0;
for(auto [u, v, idx, w] : e){
ans += w;
int p = fr[Find(u)] + 1;
while(p <= v){
ans += w;
join(u, p);
p = fr[Find(p)] + 1;
}
}
if(fr[Find(1)] != n) {
cout << -1 << endl;
return ;
}
cout << ans << endl;
}
signed main(){
ios; int _;
_ = 1; //cin >> _;
while(_--){
solve();
}
return 0;
}