2024CCPC区域赛哈尔滨站
- define时间:
#define itn int
#define int long long
#define ind long double
#define yes cout << "Yes"
#define no cout << "No"
#define pii pair<long long, long long>
#define pci pair<char, int>
#define re return;
M.Weird Ceiling
签到。简化题意:
\(f(a,b)\):如果 \(d\) 是小于等于 \(b\) 的 \(a\) 的最小约数,\(f(a,b)=a/d\);
void solve()
{
cin >> n;
ans = 0;
vector<int> v;
for (int i = 1; i <= sqrt(n); i++)
{
if (n % i == 0)
{
v.emplace_back(i);
if (i != n / i)
v.emplace_back(n / i);
}
}
sort(v.begin(), v.end());
for (int i = 0; i < v.size() - 1; i++)
{
ans += (v[i + 1] - v[i]) * (n / v[i]);
}
ans += 1;
cout << ans;
}
C. Giving Directions in Harbin
模拟。
一开始想用 map 赋值比大小来表示转向,但是忘记这是环形,所以 wa 了。
map<char, int> mp;
void solve()
{
mp['N'] = 0, mp['E'] = 1, mp['S'] = 2, mp['W'] = 3;
cin >> n;
num = 0;
for (int i = 1; i <= n; i++)
{
cin >> g[i] >> a[i];
}
cout << n * 2 - 1 << ' ' << g[1] << '\n';
g[n + 1] = g[n];
vector<char> v;
for (int i = 1; i <= n; i++)
{
cout << "Z " << a[i] << '\n';
if (g[i] == 'N' && g[i + 1] == 'W' ||
g[i] == 'W' && g[i + 1] == 'S' ||
g[i] == 'S' && g[i + 1] == 'E' ||
g[i] == 'E' && g[i + 1] == 'N')
{
cout << "L\n";
}
else if(mp[g[i]]==mp[g[i+1]])
{
1;
}
else{
cout << "R\n";
}
}
}
G. Welcome to Join the Online Meeting!
bfs。写的有点史。
入队顺序无所谓,所以先找一个非调试者入队。
然后如果他邀请的人不是调试者,那么这个人可以入队并邀请其他人。
(思路是这样,但实际都会入队,只是调试者会直接出队。)
vector<int> e[N];
int vis[N]; // 判断是否是调试程序的人
int vs[N]; // 判断是否被已经被邀请了
void solve()
{
cin >> n >> m >> k;
for (int i = 1; i <= k; i++)
{
cin >> a[i];
vis[a[i]] = 1;
}
while (m--)
{
cin >> x >> y;
e[x].emplace_back(y);
e[y].emplace_back(x);
}
queue<int> q;
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
vs[i] = 1;
q.push(i);
break;
}
}
num = 0;
/* vector<int> v(1, 0); */
vector<vector<int>> ans;
while (q.size())
{
auto u = q.front();
q.pop();
if (vis[u])
{
continue;
}
vis[u] = 1;
vector<int> tp;
tp.emplace_back(u);
for (auto i : e[u])
{
if (!vs[i])
{
tp.emplace_back(i);
q.push(i);
vs[i] = 1;
}
}
if (tp.size() > 1)
ans.push_back(tp);
}
for (int i = 1; i <= n; i++)
{
if (!vs[i])
{
no;
re;
}
}
yes;
cout << '\n';
cout << ans.size() << '\n';
for (auto i : ans)
{
cout << i[0] << ' ' << i.size() - 1 << ' ';
for (auto j = 1; j < i.size(); j++)
{
cout << i[j] << ' ';
}
cout << '\n';
}
}
K. Farm Management
贪心。
如代码注释,答案显然会在两种情况中产生:
- 考虑扩充价值最大方案为无限时间,剩余时间都给它
- 考虑对于第 i 种方案时间为 0,其余时间按价值从大到小分配
所以我们排序一下,然后前缀和存一下时间和价值,再二分一下就好了。
struct stu
{
int x, l, r;
} f[N];
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> f[i].x >> f[i].l >> f[i].r;
}
sort(f + 1, f + 1 + n, [](stu a, stu b)
{ return a.x > b.x; });
int suml = 0;
sum = 0;
for (int i = 1; i <= n; i++)
{
sum += f[i].x * f[i].l;
suml += f[i].l;
}
// 第一种情况是考虑扩充最大方案为无限时间,剩余时间都给他
ans = sum + (m - suml) * f[1].x;
// 第二种情况是考虑对于第i种方案时间为0,其余时间价值按大到小分配
for (int i = 1; i <= n; i++)
{
a[i] = a[i - 1] + f[i].r - f[i].l;
b[i] = b[i - 1] + f[i].x * (f[i].r - f[i].l);
}
for (int i = 1; i <= n; i++)
{
t = m - (suml - f[i].l); //除去i方案后总共多的时间
auto it = upper_bound(a + 1, a + 1 + n, t) - a - 1;
auto tp = sum - f[i].x * f[i].l + b[it] + f[it + 1].x * (t - a[it]);
ans = max(ans, tp);
}
cout << ans;
}
J. New Energy Vehicle
贪心。
为了距离最大化容易想到:在抵达某个充电站前尽量使用该电瓶的电。
因为充电站按顺序排放,我们可以用小顶堆来维护,一开始只放入每种电瓶最前面的一个充电站。
再用一个 next 容器来记录,这种充电站的下一个充电站位置。
每次抵达一个充电站,我们就让该种充电站的下一个充电站入堆。
void solve()
{
cin >> n >> m;
priority_queue<pii, vector<pii>, greater<>> q;
vector<int> nx(m + 1), mp(n + 1, m + 1);//加一个哨兵点,实际不存在
for (int i = 1; i <= n; i++)
{
cin >> a[i];
a1[i] = a[i];//存储电瓶容量
}
for (int i = 1; i <= m; i++)
{
cin >> b[i] >> c[i];
}
for (int i = m; i > 0; i--)
{
nx[i] = mp[c[i]]; // 记录给i充电的下个一充电站位置
mp[c[i]] = i;
}
for (int i = 1; i <= n; i++)
{
q.push({mp[i], i});
}
int ans = 0;
int cnt = 1;
while (q.size())
{
auto [x, t] = q.top();
q.pop();
int tp = b[cnt] - ans;
if (cnt <= m && a[t] >= tp)//如果这段距离小于该种电瓶电量
{
a[t] -= tp;
ans += tp;
a[c[cnt]] = a1[c[cnt]];
q.push({nx[cnt], c[cnt]});
if (a[t] && t != c[cnt])
q.push({x, t});
cnt++;
}
else
{
ans += a[t];
a[t] = 0;
}
}
cout << ans;
}

浙公网安备 33010602011771号