A. Bridging the Gap 2
最优的情况肯定是每次 R R R 人去, L L L 人回来,最后把所有的人全部送过去。
由于所有人都要到右边去,所以每个人能提供的趟数(来回算一趟)为 ( a i − 1 ) / 2 (a_i-1)/2 (ai−1)/2,除去往右去的那一次,把所有人都送到对岸要额外走的趟数为 c n t = ( n − r + ( r − l − 1 ) ) / ( r − l ) cnt=(n-r+(r-l-1))/(r-l) cnt=(n−r+(r−l−1))/(r−l) ,而每次额外的趟数都需要 l l l 个人,所以需要 c n t ∗ l cnt*l cnt∗l 点贡献,由于每个人最多走 c n t cnt cnt 趟,所以每个人的贡献为 m i n ( c n t , ( a i − 1 ) / 2 ) min(cnt,(a_i-1)/2) min(cnt,(ai−1)/2) ,对所有人的贡献求和之后与所需贡献进行比较即可,时间复杂度 O ( n ) O(n) O(n)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 2e6 + 10;
const int INF = 1e18 + 100;
const int mod = 998244353;
const int base = 23333;
void solve()
{
int n, l, r;
cin >> n >> l >> r;
int cnt = (n - r + (r - l - 1)) / (r - l);
int sum = cnt * l;
for(int i = 1;i <= n;i++)
{
int t;
cin >> t;
sum = sum - min(cnt, (t - 1) / 2);
}
if(sum <= 0) cout << YES << '\n';
else cout << NO << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}
B. MST
赛时一直在猜,猜到最后猜出来了 g c d gcd gcd。
令 d = g c d ( a 1 , a 2 , ⋯ , a n ) d=gcd(a_1,a_2,\cdots,a_n) d=gcd(a1,a2,⋯,an),答案为 m i n ( D % d , d − D % d ) min(D\%d,d-D\%d) min(D%d,d−D%d),时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)。
详细证明见官方题解。
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 998244353;
const int base = 23333;
void solve()
{
int n, D, d;
cin >> n >> D;
for(int i = 1;i <= n;i++)
{
int t;
cin >> t;
if(i == 1) d = t;
else d = __gcd(d, t);
}
cout << min(D % d, d - D % d) << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}
D. Dominoes!
把牌分成左右数字不同的和左右数字相同的两部分,由于牌可以进行翻转,所以对于左右数字不同的部分,使它左边的数字小于右边的数字,再对这些牌以左边数字为第一关键词,以右边数字为第二关键词进行升序排序。经过排序之后,从后往前放置牌一定可以使左右两两数字不同。
处理完第一类牌后,处理左右数字相同的牌。由于已经放好一部分牌了,我们再往放好的这些牌后面放牌,如何放呢。用优先队列维护不同数字牌的出现次数,每次都取出现次数最多的两个数字相同的牌,按照牌与牌之间数字不同的规则依次放下两个牌,直到优先队列中没有牌或者只有一种牌为止。
如果优先队列中还有一种牌,那么需要从前往后找可以放这个牌的位置,找到则放一个牌。如果最后队列中还有牌则输出 N o No No,否则输出 Y e s Yes Yes,再输出放好的牌的序列。还要注意特判只有一个数字相同的牌的情况,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 998244353;
const int base = 23333;
map<int, int> mp;
struct sj
{
int l, r;
} a[N];
int b[N];
bool cmp1(sj a, sj b)
{
if(a.l == b.l) return a.r < b.r;
else return a.l < b.l;
}
void solve()
{
vector<sj> ans1, ans2;
int n, t1 = 0, t2 = 0;
cin >> n;
if(n == 1)
{
int x, y;
cin >> x >> y;
cout << "Yes" << '\n';
cout << x << " " << y << '\n';
return;
}
for(int i = 1;i <= n;i++)
{
int x, y;
cin >> x >> y;
if(x > y) swap(x, y);
if(x != y) a[++t1] = {x, y};
else
{
if(!mp.count(x)) b[++t2] = x;
mp[x]++;
}
}
sort(a+1,a+t1+1,cmp1);
for(int i = t1;i >= 1;i--) ans1.push_back(a[i]);
auto cmp = [&](pii a, pii b)
{
return a.first < b.first;
};
priority_queue <pii,vector<pii>,decltype(cmp)> q(cmp);
for(int i = 1;i <= t2;i++) q.push({mp[b[i]], b[i]});
while(q.size() > 1)
{
auto [cnt1, x1] = q.top();
q.pop();
auto [cnt2, x2] = q.top();
q.pop();
if(ans1.empty())
{
ans1.push_back({x1, x1});
ans1.push_back({x2, x2});
}
else
{
if(x1 == ans1.back().r)
{
ans1.push_back({x2, x2});
ans1.push_back({x1, x1});
}
else
{
ans1.push_back({x1, x1});
ans1.push_back({x2, x2});
}
}
if(cnt1 > 1) q.push({cnt1 - 1, x1});
if(cnt2 > 1) q.push({cnt2 - 1, x2});
}
for(int i = 0;i < ans1.size();i++)
{
if(i == 0)
{
if(!q.empty() && q.top().second != ans1[i].l)
{
auto [cnt1, x1] = q.top();
q.pop();
ans2.push_back({x1, x1});
if(cnt1 > 1) q.push({cnt1 - 1, x1});
}
}
ans2.push_back(ans1[i]);
if(i < ans1.size() - 1)
{
if(!q.empty() && q.top().second != ans1[i].r && q.top().second != ans1[i + 1].l)
{
auto [cnt1, x1] = q.top();
q.pop();
ans2.push_back({x1, x1});
if(cnt1 > 1) q.push({cnt1 - 1, x1});
}
}
else
{
if(!q.empty() && q.top().second != ans1[i].r)
{
auto [cnt1, x1] = q.top();
q.pop();
ans2.push_back({x1, x1});
if(cnt1 > 1) q.push({cnt1 - 1, x1});
}
}
}
if(!q.empty()) cout << "No" << '\n';
else
{
cout << "Yes" << '\n';
for(auto [x, y] : ans2) cout << x << " " << y << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}
J. Rigged Games
先用双指针预处理出对于每个位置有一个队伍获胜一小场后下一场的开始位置。再通过倍增的方法记录下获胜 2 j ( j ≤ 19 ) 2^j (j \leq 19) 2j(j≤19) 小场后的下一场的开始位置和甲队和乙队的获胜场次,最后通过倍增从后往前遍历,直到遇到某个位置,该位置结束后整体比赛结束再停止,时间复杂度 O ( 20 n ) O(20n) O(20n)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 5e5 + 10;
const int INF = 1e18 + 100;
const int mod = 998244353;
const int base = 23333;
int pos[N][20], w[N], ga[N][20], gb[N][20];
void solve()
{
int n, a, b;
cin >> n >> a >> b;
string s;
cin >> s;
int wina = 0, winb = 0;
for(int l = 0, r = 0;l < n;l++)
{
while(wina < a && winb < a)
{
if(s[r] == '1') wina++;
else winb++;
r = (r + 1) % n;
}
if(wina == a) w[l] = 1, pos[l][0] = r, ga[l][0] = 1;
else w[l] = 0, pos[l][0] = r, gb[l][0] = 1;
if(s[l] == '1') wina--;
else winb--;
}
//for(int i = 0;i < n;i++) cout << pos[i][0] << '\n';
for(int j = 1;j <= 19;j++)
{
for(int i = 0;i < n;i++)
{
pos[i][j] = pos[pos[i][j - 1]][j - 1];
ga[i][j] = ga[i][j - 1] + ga[pos[i][j - 1]][j - 1];
gb[i][j] = gb[i][j - 1] + gb[pos[i][j - 1]][j - 1];
}
}
for(int i = 0;i < n;i++)
{
int nowa = 0, nowb = 0, p = i;
for(int j = 19;j >= 0;j--)
{
if(nowa + ga[p][j] < b && nowb + gb[p][j] < b)
{
nowa += ga[p][j];
nowb += gb[p][j];
p = pos[p][j];
}
}
if(w[p]) cout << 1;
else cout << 0;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}
L. Sudoku and Minesweeper
因为是数独,所以中间一定有 一个 8 8 8,保留这个 8 8 8 其他都输出 ∗ * ∗ 即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 998244353;
const int base = 23333;
void solve()
{
int x, y;
for(int i = 1;i <= 9;i++)
{
string s;
cin >> s;
for(int j = 0;j < 9;j++)
{
if(s[j] == '8' && j > 0 && j < 8 && i > 1 && i < 9)
{
x = i;
y = j + 1;
break;
}
}
}
for(int i = 1;i <= 9;i++)
{
for(int j = 1;j <= 9;j++)
{
if(i == x && y == j) cout << 8;
else cout << "*";
}
cout << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}