Educational Codeforces Round 25
https://codeforces.com/contest/825
ABCD没有什么意思,阅读理解题比较无聊(((
EFG不难写,但是思维比较巧,知道就是知道,不知道就写不出emm
A. Binary Protocol
#include <bits/stdc++.h>
using namespace std;
int main () {
int n;
string s;
cin >> n >> s;
int len = 0;
for (auto i : s) {
if (i == '1') len ++;
else {
cout << len;
len = 0;
}
}
cout << len;
}
B. Five-In-a-Row
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
char a[N][N];
int n = 10;
bool check(int i, int j) {
int cnt = 1;
//横向
cnt = 1;
for (int k = j + 1; k <= n; k++) {
if (a[i][k] == 'X') cnt++;
else break;
}
for (int k = j - 1; k >= 1; k--) {
if (a[i][k] == 'X') cnt++;
else break;
}
if (cnt >= 5) return true;
//纵向
cnt = 1;
for (int k = i + 1; k <= n; k++) {
if (a[k][j] == 'X') cnt++;
else break;
}
for (int k = i - 1; k >= 1; k--) {
if (a[k][j] == 'X') cnt++;
else break;
}
if (cnt >= 5) return true;
//主对角线
cnt = 1;
for (int k = 1; k + i <= n; k++) {
if (a[i + k][j + k] == 'X') cnt++;
else break;
}
for (int k = 1; i - k >= 1; k++) {
if (a[i - k][j - k] == 'X') cnt++;
else break;
}
if (cnt >= 5) return true;
//副对角线
cnt = 1;
for (int k = 1; k + i <= n && j - k >= 1; k++) {
if (a[i + k][j - k] == 'X') cnt++;
else break;
}
for (int k = 1; i - k >= 1 && j + k <= n; k++) {
if (a[i - k][j + k] == 'X') cnt++;
else break;
}
if (cnt >= 5) return true;
return false;
}
int main() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (a[i][j] == 'O') continue;
if (check (i, j)) {
cout << "YES\n";
return 0;
}
}
}
cout << "NO\n";
}
//若是放下之前就已经有能够连成的了
C. Multi-judge Solving
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3 + 5;
ll a[N], n, k, ans;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
sort (a + 1, a + n + 1);
for (int i = 1; i <= n; k = max (k, a[i++])) {
if (a[i] <= 2 * k) continue;
while (k * 2 < a[i]) k *= 2, ans ++;
//cout << k << ' ';
}
cout << ans << endl;
}
//自身是可以当作跳板的
D. Suitable Replacement
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
string s, t;
cin >> s >> t;
map<char, int> mps, mpt;
for (auto i : s) mps[i]++;
for (auto i : t) mpt[i]++;
mps['?'] = 0;
for (auto &i : s) {
if (i != '?') continue;
int minn = 1e9;
char ch;
for (char a = 'a'; a <= 'z'; a++) {
if (1ll * minn * mpt[a] > mps[a]) {
minn = mps[a] / mpt[a];
ch = a;
}
}
i = ch, mps[i] ++;
}
cout << s;
}
E. Minimal Labels
以为是差分约束,怎么是字典序最大的逆拓扑序??
// LUOGU_RID: 103196572
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, M = 3e5 + 5;//不是很懂为什么是这么大
int n, m, d[N], ans[N];
int h[N], e[M], ne[M], idx;
void add (int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void topsort(){
priority_queue<int> q; //为什么是优先队列: 字典序最大的top序
for(int i = 1;i <= n; ++i) if(d[i] == 0) q.push(i);
int tot = n;
while(q.size()){
int t = q.top();
ans[t] = tot--;
q.pop();
for(int i = h[t];i != -1; i = ne[i]){
int j = e[i];
d[j] --;// j 的入度 --
if(d[j] == 0) q.push(j);
}
}
}
int main () {
memset (h, -1, sizeof h);
cin >> n >> m;
while (m --) {
int a, b; //a < b
cin >> a >> b;
add (b, a);
d[a] ++;
}
topsort ();
for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
}
//逆拓扑序从大到小排
F. String Compression
dp + kmp蛮不错的小题
涉及到对kmp的理解,求循环节那块
(可能比较板?!)
对后缀进行next数组求解
// LUOGU_RID: 103202632
#include <bits/stdc++.h>
using namespace std;
const int N = 8005;
int f[N], cnt[N], nxt[N]; //f[i]: 压缩到i时的答案, cnt[i]: i的位数
char s[N];
void kmp(char *s, int len, int nxt[]) {
//cout << s << endl;
nxt[0] = nxt[1] = 0;
for(int i = 1; i < len; ++i) {
int j = nxt[i];
while(j && s[i]!=s[j]) j=nxt[j];
if (s[j] == s[i]) nxt[i+1] = j + 1;
else nxt[i+1] = 0;
}
}
int main () {
cin >> s;
int n = strlen (s);
for (int i = 1; i <= n; i++) {
cnt[i] = cnt[i/10] + 1, f[i] = i + 1; //字符+个数1
}
for (int i = 0; i < n; i++) {
kmp (s + i, n - i, nxt); //截取i为起点的后缀[i,n)
for (int j = 1; j + i <= n; j++) { //区间[i,i+j)
int len = j - nxt[j]; //最长循环节
if (j % len) f[i+j] = min (f[i+j], f[i] + j + 1);
else f[i+j] = min (f[i+j], f[i] + len + cnt[j/len]);
}
}
cout << f[n] << endl;
}
//dp + kmp(nxt数组)
//nxt[i]: 后缀i可以匹配的最长前缀
//[nxt[i],i]: 以i结尾的循环串
G. Tree Queries
取巧(思维!?)
以第一个黑点为根,\(a_i\) 记录 \(i\) 到根上最小点的编号,则所有点的求解都可转化为 \(a_i\)。分为在/不在同一根上,都是直接记录最小值即可。根作为中介已经能转化了。
// LUOGU_RID: 103207434
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5, M = N * 2;
int a[N], n, q; //a[i]: i到根上最小的点的编号
int h[N], e[M], ne[M], idx;
void add (int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs (int u, int fa) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == fa) continue;
a[j] = min (j, a[u]);
dfs (j, u);
}
}
int main () {
memset (h, -1, sizeof h);
scanf ("%d%d", &n, &q);
for (int i = 1; i < n; i++) {
int a, b;
scanf ("%d%d", &a, &b);
add (a, b), add (b, a);
}
int lst = 0, ans = 1e9, fst = 0;
while (q--) {
int op, x;
scanf ("%d%d", &op, &x);
x = (x + lst) % n + 1;
if (op == 1) {
if (fst == 0) a[x] = x, fst = 1, dfs (x, -1); //以第一个黑为根
ans = min (ans, a[x]);
}
else {
lst = min (ans, a[x]);
printf ("%d\n", lst);
}
}
}
//在不在一条路上的都可以转化
标签:25,Educational,idx,int,Codeforces,++,cnt,using,include
From: https://www.cnblogs.com/CTing/p/17161776.html