Codeforces Round #797 (Div. 3) A - F
现在还在 hack 期间,要是被 hack 了就再更新代码
G 还挺感兴趣的,找时间看看题
A - Print a Pedestal (Codeforces logo?)
对 3 取模的三种情况进行构造
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int num[10];
int main()
{
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
num[0] = num[1] = num[2] = n / 3;
num[1]++;
num[2]--;
n = n % 3;
if(n >= 1)
num[1]++;
if(n >= 2)
num[0]++;
for(int i=0; i<3; i++) cout << num[i] << " ";
cout << endl;
}
return 0;
}
B - Array Decrements
把 \(b_i\) 是 0 和不是 0 的情况分开讨论,不是 0 的要求一致,是 0 的情况,要求都不超过不是 0 的 \(a_i\) 的减少次数
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int a[maxn], b[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
for(int i=0; i<n; i++) cin >> a[i];
for(int i=0; i<n; i++) cin >> b[i];
int f = 1, way = -1;
int x = -1;
for(int i=0; i<n; i++)
{
if(b[i] > a[i]) f = 0;
if(b[i] == 0) {x = max(x, a[i] - b[i]); continue;}
if(way == -1) way = a[i] - b[i];
else
{
if(a[i] - b[i] != way) f = 0;
}
}
if(f && x != -1 && way != -1 && x > way)
f = 0;
if(f) cout << "yes" << endl;
else cout << "no" << endl;
}
return 0;
}
C - Restoring the Duration of Tasks
区间合并处理,开场就有序了,所以不用排序
只要记录更新当前时间即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
pii seg[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
for(int i=0; i<n; i++)
cin >> seg[i].first;
for(int i=0; i<n; i++)
cin >> seg[i].second;
int now = 0;
for(int i=0; i<n; i++)
{
now = max(now, seg[i].first);
int ans = max(0, seg[i].second - now);
now = max(now, seg[i].second);
cout << ans << " ";
}
cout << endl;
}
return 0;
}
D - Black and White Stripe
尺取
k 就是长度,直接判断每一个长度 为 k 的子串有多少个 W 出现即可,然后取每个区间的最小值
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
pii seg[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n, k;
string s;
cin >> n >> k >> s;
int l = 0, r = 0;
int ans = s.length();
int now = 0;
while(1)
{
while(r < s.length() && r - l < k)
now += s[r++] == 'W';
if(r - l != k) break;
ans = now < ans ? now : ans;
now -= s[l++] == 'W';
}
cout << ans << endl;
}
return 0;
}
E - Small d and k
显然按照对 k 的同余系分类,按照一下策略进行:
选择两个数,在满足余数之和不小于 k 的前提下,尽量使最大的和最小的凑在一起
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
ll num[maxn], vis[maxn];
ll n, k;
bool cmp(const ll& a, const ll& b)
{
return a % k < b % k;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
cin >> n >> k;
for(int i=0; i<n; i++) {cin >> num[i]; vis[i] = 0;}
sort(num, num + n, cmp);
int l = 0, r = n - 1;
ll ans = 0;
while(l < r)
{
while(l < r && num[l] % k + num[r] % k < k) l++;
if(l >= r) break;
vis[l] = vis[r] = 1;
ans += (num[l] + num[r]) / k;
l++;
r--;
}
int pre = -1;
for(int i=0; i<n; i++)
{
if(vis[i]) continue;
if(pre == -1) pre = num[i];
else
{
ans += (pre + num[i]) / k;
pre = -1;
}
}
cout << ans << endl;
}
return 0;
}
F - Shifting String
对排列进行 dfs 的话,显然会形成一个环,就考虑这个环能否回到最初
因此答案就是求每个环的最小循环节的最小公倍数
求循环节的话,考虑到串并不长,可暴力,可 kmp
这题一直卡在求错了若干个数的最小公倍数上,麻了,一直以为思路错了,想不到是自己蠢
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int vis[maxn], num[maxn], nex[maxn];
string ss, s;
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
void getnext()
{
int len = ss.length(), j = -1, i = 0;
nex[0] = -1;
while(i < len)
{
if(j == -1 || ss[j] == ss[i])
nex[++i] = ++j;
else
j = nex[j];
}
}
void dfs(int now, ll& tot)
{
if(vis[now]) return;
tot++;
vis[now] = 1;
ss += s[now];
dfs(num[now], tot);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n >> s;
s = "a" + s;
for(int i=1; i<=n; i++) {cin >> num[i]; vis[i] = 0;}
vector<ll>v;
for(int i=1; i<=n; i++)
{
ll ans = 0;
if(vis[i]) continue;
ss = "";
dfs(i, ans);
getnext();
ll x = ss.length() - nex[ss.length()];
if(x && ss.length() % x == 0) ans = x;
v.push_back(ans);
}
ll ans = 1;
for(int i=0; i<v.size(); i++)
{
ll x = gcd(ans, v[i]);
ans = ans / x * v[i];
}
cout << ans << endl;
}
return 0;
}