20260726
P2587 [ZJOI2008] 泡泡堂
这题真的只有绿吗。
思路
考虑如下贪心策略:
- 如果当前我方最小打得过对方最小,那么就打。
- 如果当前我方最大打得过对方最大,那么就打。(因为下面的操作是将对方最大的耗掉,我们既然能打过,那么为什么要耗掉呢?)。
- 我方最小和对方最大玉碎,因为对方最大太强了,谁都打不过,最优的情况是用我方最小耗掉他。
我方最坏情况即对方最优情况,不用再分类一遍了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], b[N];
int work(int a[], int b[])
{
int res = 0;
int l = 1, r = n, mi = 1, ma = n;
while(l <= r && mi <= ma)
{
if(a[mi] > b[l])
{
mi ++, l ++;
res += 2;
}
else if(a[ma] > b[r])
{
ma --, r --;
res += 2;
}
else
{
if(a[mi] == b[r]) res ++;
mi ++, r --;
}
}
return res;
}
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) cin >> b[i];
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
cout << work(a, b) << " " << n * 2 - work(b, a) << endl;
}
P6927 [ICPC 2016 WF] Swap Space
思路
考虑将硬盘分成两类,然后排个序,贪心即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, ans, sum;
struct node
{
int a, b;
};
vector<node> v1, v2;
bool cmp1(node a, node b) {return a.a < b.a;}
bool cmp2(node a, node b) {return a.b > b.b;}
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
int a, b; cin >> a >> b;
if(a < b) v1.push_back({a, b});
else v2.push_back({a, b});
}
sort(v1.begin(), v1.end(), cmp1);
sort(v2.begin(), v2.end(), cmp2);
for(int i = 0; i < v1.size(); i ++)
{
ans = min(ans, sum - v1[i].a);
sum += (v1[i].b - v1[i].a);
}
for(int i = 0; i < v2.size(); i ++)
{
ans = min(ans, sum - v2[i].a);
sum += (v2[i].b - v2[i].a);
}
cout << -ans << endl;
}
P8113 [Cnoi2021] 自我主义的平衡者
思路
考虑贪心。
不难发现,\(a_i\) 从小到大排序时,平均分是最高的。\(a_i\) 从大到小排序时,平均分是最低的。
证明:
将 \(a_i\) 从小到大排序:
- 当前平均分还很低时,前面的 \(a_i\) 更愿意打满分,一旦打了满分,平均分就会被抬高。
- 如果平均分已经超过他们的心理预期,他们就会打 \(0\) 分,且拉低平均分,方便后面的人打满分。
- 因为数组已经升序排列,\(a_i\) 会越来越大。前面有人打 \(0\) 分压低平均分后,后面的 \(a_i\) 就更容易打满分。
将 \(a_i\) 从大到小排序:
- 前面的 \(a_i\) 会将平均分拉的很高,那么后面的人就会几乎全部打 \(0\) 分,将平均分拉的很低。
- 因为满分 \(m\) 是最高分,一旦前期把平均分抬高,后面再打 \(0\) 分也只能缓慢拉低,但很难再降到一个让挑剔者重新打满分的水平。这样满分就基本被“锁死”在前几个\(a_i\) 上,后续的人全在打 \(0\) 分,总分自然最小。
警示后人:
- 小心精度问题。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int ans, a[100005], n, m, ans1;
signed main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i ++)
{
if(ans <= a[i] * (i - 1))
{
ans += m;
}
}
for(int i = n; i >= 1; i --)
{
if(ans1 <= a[i] * (n - i))
{
ans1 += m;
}
}
double cnt1 = ans * 1.0 / n, cnt2 = ans1 * 1.0 / n;
printf("%.2lf %.2lf\n", cnt1, cnt2);
}
P1456 Monkey King
思路
直接启发式合并。
开 \(n\) 个优先队列,除了合并时小的合并到大的以外,其他的和暴力差不多。
注意需要开一个数组存储一个元素当前在的优先队列的编号。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5;
struct node
{
int x, id;
bool operator<(const node qwq) const
{
return qwq.x > x;
}
};
priority_queue<node> q[N];
int n, cur[N], m, a[N];
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
q[i].push({a[i], i});
cur[i] = i;
}
cin >> m;
while(m --)
{
int x, y; cin >> x >> y;
int u = cur[x], v = cur[y];
if(u == v)
{
cout << -1 << endl;
continue;
}
if(v < u) swap(u, v);
q[u].push({q[u].top().x / 2, q[u].top().id});
q[u].pop();
q[v].push({q[v].top().x / 2, q[v].top().id});
q[v].pop();
if(u <= v)
{
cur[x] = v;
while(!q[u].empty())
{
q[v].push(q[u].top());
cur[q[u].top().id] = v;
q[u].pop();
}
}
cout << q[v].top().x << endl;
}
}
P1902 刺杀大使
思路
二分答案。
二分判断就dfs判断连通性就好了,如果一个点的值大于我们二分的那个答案,则不能走。
注意到dfs不能回溯,因为这个点一旦走不通,则没必要再走一遍。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n, m, a[1005][1005], flag, vis[1005][1005];
int fx[4] = {0, 0, 1, -1}, fy[4] = {1, -1, 0, 0};
void dfs(int x, int y, int val)
{
if(x == n)
{
flag = 1;
return ;
}
if(flag == 1) return ;
for(int i = 0; i < 4; i ++)
{
int xx = x + fx[i], yy = y + fy[i];
if(!vis[xx][yy] && xx >= 1 && yy >= 1 && xx <= n && yy <= m && a[xx][yy] <= val)
{
vis[x][y] = 1;
dfs(xx, yy, val);
// vis[x][y] = 0;
}
}
}
bool check(int x)
{
flag = 0;
memset(vis, 0, sizeof(vis));
dfs(1, 1, x);
return flag;
}
signed main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
cin >> a[i][j];
}
}
int l = 0, r = 1000;
while(l <= r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout << r + 1 << endl;
}

浙公网安备 33010602011771号