Codeforces Round 974 (Div. 3)题解记录
A.Robin Helps
签到模拟,遍历一遍即可,注意没钱时不给钱。\(O(n)\)
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, k;
cin >> n >> k;
ll ans = 0;
ll cnt = 0;
for (ll i = 1; i <= n; i++)
{
ll x;
cin >> x;
if (x >= k)
{
ans += x;
}
if (x == 0)
{
if (ans > 0)
ans--, cnt++;
}
}
cout << cnt << endl;
}
}
B.Robin Helps
一段区间\(i^i\)之和的奇偶性与这段区间内的i之和的奇偶性时相同的。本题注意是求符合区间到第n年的奇偶性.
这题看错成n年之内区间和是否出现偶数了,错了两次。代码写丑陋了.\(O(1)\)
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, k;
cin >> n >> k;
if (n == 1)
{
cout << "NO" << endl;
continue;
}
else if (n%2==0)
{
k = min(k, n);
if ((k / 2) % 2 == 0)
{
cout << "YES" << endl;
}
else
cout << "NO" << endl;
continue;
}
else
{
if (n <= k)
{
if ((n / 2 + 1) % 2 == 0)
cout << "YES" << endl;
else
cout << "NO" << endl;
continue;
}
else
{
if (k % 2 == 0)
{
if ((k / 2) % 2 == 0)
cout << "YES" << endl;
else
cout << "NO" << endl;
continue;
}
else
{
if ((k / 2 + 1) % 2 == 0)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
continue;
}
}
}
}
C. Robin Hood in Town
本题题意就是\(ai\)中最大值加多少可以使所有\(ai\)小于平均金额的一半的人的个数大于\(n/2\),直接二分.注意解决精度问题。
我是二分加多少,一开始\(r\)值写小了,错了一次,\(r\)值至少得大于等于\(1.99998e11\)。\(O(n*log(1e18))\)
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
ll a[200005];
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n;
cin >> n;
for (ll i = 1; i <= n; i++)cin >> a[i];
if (n == 1 || n == 2)
{
cout << -1 << endl;
continue;
}
sort(a + 1, a + 1 + n);
ll sum = 0;
for (ll i = 1; i <= n; i++)
{
sum += a[i];
}
ll l = 0, r = 1e18;
while (l < r)
{
ll mid = (l + r) >> 1;
ll k = sum + mid;
ll cnt = 0;
for (ll i = 1; i <= n-1; i++)
{
if (a[i] * n*2 < k)
{
cnt++;
}
}
if (cnt * 2 > n)
{
r = mid;
}
else
l = mid + 1;
}
cout << r << endl;
}
}
D. Robert Hood and Mrs Hood
维护区间不同工作个数即可,同时维护一个最大值位置和最小值位置.
用了优先队列+双指针维护合理区间.\(O(nlogn)\)
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
vector<ll>g[250000];
ll a[200005];
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n,d,k;
cin >> n >> d >> k;
for (ll i = 1; i <= k; i++)
{
ll l, r;
cin >> l >> r;
a[i] = l;
g[l].push_back(r);
}
// priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,greater<pair<ll,ll>>>q1;
priority_queue<ll,vector<ll>,greater<ll>>f;
ll co = 0,ko=99999999999;
ll ans = 0;
ll s1, s2;
ll l = 0, r = 0;
for (ll i = 1; i <= n; i++)
{
if (l == 0 && r == 0)
{
l = 1, r = 1;
for (auto j : g[i])
{
f.push(j);
ans++;
}
if (r - l + 1 == d)
{
if (co < ans)
{
co = ans;
s1 = l;
}
if (ko > ans)
{
ko = ans;
s2 = l;
}
}
}
else if (r - l + 1 < d)
{
for (auto j : g[i])
{
f.push(j);
ans++;
}
r++;
if (r - l + 1 == d)
{
if (co < ans)
{
co = ans;
s1 = l;
}
if (ko > ans)
{
ko = ans;
s2 = l;
}
}
}
else
{
while (!f.empty() && f.top() <= l)
{
ans--;
f.pop();
}
for (auto j : g[i])
{
f.push(j);
ans++;
}
l++;
r++;
if (r - l + 1 == d)
{
if (co < ans)
{
co = ans;
s1 = l;
}
if (ko > ans)
{
ko = ans;
s2 = l;
}
}
}
}
cout << s1 << " " << s2 << endl;
for (ll i = 1; i <= n; i++)
{
g[i].clear();
}
}
}
E. Rendez-vous de Marian et Robin
感觉是div3里对我来说最难得题了
先处理一遍1到所有点的最短路,再考虑马点的最短路。由于dijkstra特性每次到了最近的马点再返回,后续到了新马点就不用再走之前返回过了的点,vis起作用了
于是一次dijkstra的时间复杂度最大为\(2*(m+nlogn)\).
最后再处理n到所有点的最短路,总时间复杂度为\(4*(m+nlogn)\)
最后答案走一遍\(max(dp1[i],dp2[i])\)的最小值即可\(O(4*(m+nlogn))\)
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
ans *= x;
x *= x;
y >>= 1;
}
return ans;
}
ll house[200005];
vector<pair<ll, ll>>g[200005];
ll n, m, h;
bool vis[200005][2];
void dij(ll a[][2], ll x)
{
priority_queue<pair<ll, pair<ll, ll>>, vector<pair<ll, pair<ll, ll>>>, greater<pair<ll, pair<ll, ll>>>>q;
a[x][0] = 0;
q.push({ a[x][0],{x,0} });
for (ll i = 1; i <= n; i++)vis[i][0] = vis[i][1] = 0;
while (!q.empty())
{
ll x = q.top().second.first;
ll hu = q.top().second.second;
q.pop();
if (vis[x][hu])continue;
vis[x][hu] = 1;
if (hu == 0 && house[x])
{
a[x][1] = min(a[x][0],a[x][1]);
q.push({ a[x][1],{x,1} });
}
for (auto j : g[x])
{
ll nx = j.first;
ll w = j.second;
if (!vis[nx][hu])
{
if (hu == 0)
{
if (a[nx][hu] > a[x][hu] + w)
{
a[nx][hu] = a[x][hu] + w;
q.push({ a[nx][hu],{nx,hu} });
}
}
else
{
if (a[nx][hu] > a[x][hu] + w/2)
{
a[nx][hu] = a[x][hu] + w/2;
q.push({ a[nx][hu],{nx,hu} });
}
}
}
}
}
for (ll i = 1; i <= n; i++)
{
a[i][0] = min(a[i][1], a[i][0]);
}
return;
}
ll dp1[200005][2];
ll dp2[200005][2];
int main()
{
ll t;
cin >> t;
while (t--)
{
cin >> n >> m >> h;
for (ll i = 1; i <= n; i++)house[i] = 0, g[i].clear();
while (h--)
{
ll x;
cin >> x;
house[x] = 1;//表示马点
}
while (m--)
{
ll l, r, w;
cin >> l >> r >> w;
g[l].push_back({ r,w });
swap(l, r);
g[l].push_back({ r,w });
}
for (ll i = 1; i <= n; i++)
{
dp1[i][0] = dp1[i][1] = dp2[i][0] = dp2[i][1] = 999999999999999;
}
dij(dp1, 1);
dij(dp2, n);
if (dp1[n][0] == 999999999999999)
{
cout << -1 << endl;
}
else
{
ll ans = 999999999999999;
for (ll i = 1; i <= n; i++)
{
ll u = max(dp1[i][0] , dp2[i][0]);
ans = min(ans, u);
}
cout << ans << endl;
}
}
}
F. Sheriff's Defense
直接dp即可,保或者不保回溯即可
这里一开始想成优先队列枚举了,尴尬。没直接盯帧dp
\(O(n)\)
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
ll dp[200005][2];
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
vector<ll>g[250000];
ll a[250000];
bool vs[250000];
ll n, m, k;
void dfs(ll x)
{
if (vs[x])
return;
vs[x] = 1;
dp[x][1] = a[x];
dp[x][0] = 0;
for (auto j : g[x])
{
if (vs[j])
continue;
dfs(j);
dp[x][1] += max(dp[j][0], dp[j][1]-k*2);
dp[x][0] += max(dp[j][0], dp[j][1]);
}
}
int main()
{
ll t;
cin >> t;
while (t--)
{
cin >> n >> k;
for (ll i = 1; i <= n; i++)cin >> a[i], vs[i] = 0, g[i].clear();
for(ll i=1;i<=n-1;i++)
{
ll l, r;
cin>> l >> r;
g[l].push_back(r);
g[r].push_back(l);
}
dfs(1);
cout << max(dp[1][1], dp[1][0]) << endl;
}
}
G. Milky Days
思路很明显,用堆栈维护最新的牛奶即可,考虑到没有新牛奶的时候和有新牛奶的时候
过保质期或者没牛奶了弹出。
写复杂了,哈哈。这里一开始错\(WA2\)了,原因在于\(u==uo\)的时候减少的数量不是理想数量\(jo\)
\(O(nlogn)\)
//难改
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<time.h>
#include<random>
using namespace std;
typedef long long ll;
mt19937 rnd(time(0));
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
ans *= x;
x *= x;
y >>= 1;
}
return ans;
}
ll a[250000];
ll hh[250000];
//stack<pair<ll, ll>>q;
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n,m,k;
cin >> n >> m >> k;
for (ll i = 1; i <= n; i++)// 栈+模拟?
cin >> a[i] >> hh[i];
stack<pair<ll, ll>>q;
ll u = 0;
ll ans = 0;
for (ll i = 1; i <= n; i++)
{
if (q.empty())
{
u = a[i];
hh[i] -= m;
if (hh[i] >= 0)ans++;
if (hh[i] > 0)
q.push({ a[i] + k - 1,hh[i] });
}
else
{
ll uo = a[i] - 1;
ll cnt = 0;
while (!q.empty())
{
if (q.top().first <= u)
{
q.pop();
continue;
}
if (u == uo)
break;
if (cnt == 0)
{
ll of = q.top().first;
ll ok = q.top().second;
ll jo = ok / m;
ll wc = u + jo;
wc = min(wc, uo);
wc = min(wc, of);
ans += wc - u;
ll zo = wc - u;
u = wc;
if (wc == uo)//最后一天
{
q.pop();
if (ok > zo*m)
{
q.push({ of,ok - zo * m });
}
continue;
}
else if (wc == of)// 保质期
{
q.pop();
continue;
}
else //非最后一天,非保质期
{
q.pop();
cnt = ok % m;//看剩余
}
}
else
{
while (!q.empty())
{
ll of = q.top().first;
if (of <= u)//先把剩下的去除
{
q.pop();
continue;
}
ll ok = q.top().second;
if (cnt +ok >= m)
{
ok -= (m - cnt);
cnt = 0;
q.pop();
q.push({ of,ok });
ans++;
break;
}
else
{
cnt += ok;
q.pop();
}
}
cnt = 0;
u++;
}
}
if (hh[i] >= m)
{
ans++;
hh[i] -= m;
if(hh[i]>0)
q.push({ a[i] + k - 1,hh[i] });
u = a[i];
continue;
}
cnt = hh[i];
while (!q.empty())
{
ll of = q.top().first;
ll ok = q.top().second;
if (of <= u)
{
q.pop();
continue;
}
else
{
if (ok + cnt >= m)
{
ans++;
ok -= (m - cnt);
q.pop();
if(ok>0)
q.push({ of,ok });
break;
}
else
{
cnt += ok;
q.pop();
continue;
}
}
}
u++;
}
}
ll cnt = 0;
while (!q.empty())
{
ll of = q.top().first;
ll ok = q.top().second;
if (of <= u)
{
q.pop();
continue;
}
if (cnt == 0)
{
ll wc = ok / m + u;
if (wc >= of)
{
wc = of;
ans += wc-u;
u = wc;
cnt = 0;
q.pop();
continue;
}
else
{
ans += wc-u;
u = wc;
cnt = ok % m;
q.pop();
}
}
else
{
while (!q.empty())
{
ll of = q.top().first;
ll ok = q.top().second;
if (of <= u)
{
q.pop();
continue;
}
if (cnt + ok >= m)
{
ans++;
ok -= (m - cnt);
q.pop();
cnt = 0;
if(ok>0)
q.push({ of,ok });
break;
}
else
{
cnt += ok;
q.pop();
}
}
cnt = 0;
u++;
}
}
cout << ans << endl;
}
}
H. Robin Hood Archery
挺惊讶的一道题,思路从数组前缀异或和->线段树->随机数飘了一遍
最后随机数解决了这道题.偶数反例:2,4,8,14.
随机数大概率减少了这种情况发生。\(O(nlogn)\)级别左右
//看命
#include<iostream>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<bitset>
#include<math.h>
#include<string>
#include<string.h>
#include<stack>
#include<queue>
#include<time.h>
#include<random>
using namespace std;
typedef unsigned long long ll;
mt19937 rnd(time(0));
ll gcd(ll a, ll b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
ans *= x;
x *= x;
y >>= 1;
}
return ans;
}
ll a[250000];
ll hh[250000];
map<ll, ll>q,f;
void fio()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, m;
cin >> n >> m;
for (ll i = 1; i <= n; i++)
{
cin >> a[i];
if (q[a[i]] == 0)
{
ll k = rnd();
while (f[k] != 0)
{
k = rnd();
}
f[k]++;
q[a[i]] = k;
a[i] = k;
}
else
a[i] = q[a[i]];
}
ll u = 0;
for (ll i = 1; i <= n; i++)
{
hh[i] = a[i] ^ hh[i - 1];//异或前缀和?
}
while (m--)
{
ll l, r;
cin >> l >> r;
if ((r - l + 1) % 2)
{
cout << "NO" << endl;
}
else
{
if ((hh[r] ^ hh[l - 1]) == 0)
{
cout << "YES" << endl;
}
else
cout << "NO" << endl;
}
}
}
}