2024ICPC昆明邀请赛个人题解
题解火车头
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <unordered_map>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <list>
#include <bitset>
#include <cmath>
#include <numeric>
#define endl '\n'
#define ft first
#define sd second
#define yes cout << "yes\n"
#define no cout << "no\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define unq_all(x) x.erase(unique(all(x)), x.end())
#define sort_all(x) sort(all(x))
#define reverse_all(x) reverse(all(x))
#define INF 0x7fffffff
#define INFLL 0x7fffffffffffffffLL
#define RED cout << "\033[91m"
#define GREEN cout << "\033[92m"
#define YELLOW cout << "\033[93m"
#define BLUE cout << "\033[94m"
#define MAGENTA cout << "\033[95m"
#define CYAN cout << "\033[96m"
#define RESET cout << "\033[0m"
// 红色
#define DEBUG1(x) \
RED; \
cout << #x << " : " << x << endl; \
RESET;
// 绿色
#define DEBUG2(x) \
GREEN; \
cout << #x << " : " << x << endl; \
RESET;
// 蓝色
#define DEBUG3(x) \
BLUE; \
cout << #x << " : " << x << endl; \
RESET;
// 品红
#define DEBUG4(x) \
MAGENTA; \
cout << #x << " : " << x << endl; \
RESET;
// 青色
#define DEBUG5(x) \
CYAN; \
cout << #x << " : " << x << endl; \
RESET;
// 黄色
#define DEBUG6(x) \
YELLOW; \
cout << #x << " : " << x << endl; \
RESET;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ld, ld> pdd;
typedef pair<string, string> pss;
typedef pair<string, int> psi;
typedef pair<string, ll> psl;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
typedef vector<pss> vpss;
typedef vector<vi> vvi;
typedef vector<vl> vvl;
typedef queue<int> qi;
typedef queue<ll> ql;
typedef queue<pii> qpii;
typedef queue<pll> qpll;
typedef queue<psi> qpsi;
typedef queue<psl> qpsl;
typedef priority_queue<int> pqi;
typedef priority_queue<ll> pql;
typedef priority_queue<string> pqs;
typedef priority_queue<pii> pqpii;
typedef priority_queue<psi> pqpsi;
typedef priority_queue<pll> pqpl;
typedef priority_queue<psi> pqpsl;
typedef map<int, int> mii;
typedef map<int, bool> mib;
typedef map<ll, ll> mll;
typedef map<ll, bool> mlb;
typedef map<char, int> mci;
typedef map<char, ll> mcl;
typedef map<char, bool> mcb;
typedef map<string, int> msi;
typedef map<string, ll> msl;
typedef map<int, bool> mib;
typedef unordered_map<int, int> umii;
typedef unordered_map<ll, ll> uml;
typedef unordered_map<char, int> umci;
typedef unordered_map<char, ll> umcl;
typedef unordered_map<string, int> umsi;
typedef unordered_map<string, ll> umsl;
template <typename T>
inline void read(T &x)
{
T f = 1;
x = 0;
char ch = getchar();
while (0 == isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (0 != isdigit(ch))
x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
x *= f;
}
template <typename T>
inline void write(T x)
{
if (x < 0)
{
x = ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
A. Two-star Contest
题目描述
样例
输入
5
3 4 5
5 1 3 -1 -1
2 -1 5 -1 5
3 3 -1 -1 4
2 3 10
10000 5 0 -1
1 10 10 10
2 3 10
10 1 2 3
100 4 5 6
2 3 10
100 1 2 3
10 4 5 6
2 3 10000
100 -1 -1 -1
1 -1 -1 -1
输出
Yes
1 3 5 4
0 5 0 5
3 3 2 4
No
Yes
1 2 3
4 5 6
No
Yes
2024 5 26
11 45 14
解题思路
按星级排个序,对于每个星级贪心地维护可以允许的下限就行了。
赛时这题是队友写的,搓起来太麻烦,不想写了
B. Gold Medal
题目描述
样例
输入
2
3 10
239 141 526
6
2 1
300 100
1000
输出
91
1400
解题思路
先计算出每场比赛还差多少只队伍就刚好多一个金牌, a i = k − a i a_i=k-a_i%k ai=k−ai。然后从小到大贪心的去补齐,然后再将剩余的队伍数除 k k k,加入最后答案。
题解
void solve()
{
ll n, k;
cin >> n >> k;
vl a(n);
ll ans = 0;
for (ll i = 0; i < n; i++)
{
cin >> a[i];
ans += a[i] / k;
a[i] = k - a[i] % k;
}
ll m;
cin >> m;
sort_all(a);
for (ll i = 0; i < n; i++)
{
if (a[i] <= m)
{
m -= a[i];
ans++;
}
else
break;
}
ans += m / k;
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int _ = 1;
std::cin >> _;
while (_--)
{
solve();
}
return 0;
}
G. Be Positive
题目描述
样例
输入
4
1
2
3
4
输出
impossible
1 0
1 0 2
impossible
解题思路
异或和的性质:对于 0 ∼ n 0 \sim n 0∼n的连续异或和,每个四个数异或和为 0 0 0。所以我们只需要对于每四个数,把它和后面的数交换一下,就可以得到最小字典序的前缀异或和不为 0 0 0的序列。这个性质的具体推导过程可以去看我武汉邀请赛的那篇题解。
注:最开头的 0 0 0和 1 1 1需要交换一下
题解
void solve()
{
int n;
cin >> n;
if (n == 1 || n % 4 == 0)
{
cout << "impossible" << endl;
return;
}
vi ans(n);
for (int i = 0; i < n; i++)
{
ans[i] = i;
}
swap(ans[0], ans[1]);
for (int i = 4; i < n; i += 4)
{
swap(ans[i], ans[i - 1]);
}
for (auto &x : ans)
cout << x << " ";
cout << endl;
}
int main()
{
ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int _ = 1;
std::cin >> _;
while (_--)
{
solve();
}
return 0;
}
I. Left Shifting 2
解题思路
无论如何我们怎么左移,最多只能让操作次数减1,所以判断那些情况操作次数可以减1就行了。
官方题解是把字符串左移直到首尾不同然后判断有没有偶数长度的连续块,有的话就对答案减1,我们赛场上的做法是分类讨论首尾是否相同的情况。
题解
void solve()
{
int n;
cin >> n;
if (n == 1 || n % 4 == 0)
{
cout << "impossible" << endl;
return;
}
vi ans(n);
for (int i = 0; i < n; i++)
{
ans[i] = i;
}
swap(ans[0], ans[1]);
for (int i = 4; i < n; i += 4)
{
swap(ans[i], ans[i - 1]);
}
for (auto &x : ans)
cout << x << " ";
cout << endl;
}
int main()
{
ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int _ = 1;
std::cin >> _;
while (_--)
{
solve();
}
return 0;
}
M. Italian Cuisine
题目描述
输入
3
5
1 1 1
0 0
1 0
5 0
3 3
0 5
6
2 4 1
2 0
4 0
6 3
4 6
2 6
0 3
4
3 3 1
3 0
6 3
3 6
0 3
输出
5
24
0
解题思路
经典的旋转卡壳问题,用双指针在图包上旋转就行
题解
typedef __int128_t lll;
typedef pair<lll, lll> P;
#define x first
#define y second
// 叉乘
lll cross(P a, P b)
{
return a.x * b.y - a.y * b.x;
}
// 点积
lll mul(P a, P b)
{
return a.x * b.x + a.y * b.y;
}
// 点平方和
lll mul(P a)
{
return a.x * a.x + a.y * a.y;
}
// 计算矢量
P del(P a, P b)
{
return {a.x - b.x, a.y - b.y};
}
void solve()
{
int n;
read(n);
P C;
read(C.x);
read(C.y);
lll R;
read(R);
vector<P> a(n);
for (int i = 0; i < n; i++)
{
read(a[i].x);
read(a[i].y);
}
lll ans = 0;
lll S = 0;
for (int l = 0, r = l + 1; l < n; l++)
{
while (1)
{
// 处理首尾循环
int rr = r % n + 1;
// 计算新加点是否在左边界与圆心连线的另一侧
lll s = cross(del(a[rr], a[l]), del(C, a[l]));
// 如果在另一侧,说明新加边与圆相交或凸包包含了圆,移动l
if (s <= 0)
break;
// s同时也是新加边与圆心构成的三角形的面积的两倍,利用s=len*d计算边与圆心的距离
// 如果距离小于R,说明新加边与圆相交,移动l
if (s * s < mul(del(a[rr], a[l])) * R * R)
break;
// 利用叉乘公式计算凸包新增加的三角形面积
S += cross(del(a[r], a[l]), del(a[rr], a[l]));
// 移动r
r = rr;
}
ans = max(ans, S);
// 处理首尾循环
int ll = l % n + 1;
// 减去左边界的三角形面积
S -= cross(del(a[r], a[l]), del(a[r], a[ll]));
}
write(ans);
putchar('\n');
}
int main()
{
// ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int _ = 1;
// std::cin >> _;
read(_);
while (_--)
{
solve();
}
return 0;
}