Educational Codeforces Round 138 (Rated for Div. 2)题解 (A-C)
A.Cowardly Rooks
dfs暴搜即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#define ll long long
template <class T>
inline void read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
a = x * s;
return ;
}
int n, m;
int fx[5] = {0, 1, -1, 0, 0};
int fy[5] = {0, 0, 0, 1, -1};
int x[N], y[N];
int a[10][10];
bool flag = 0;
bool check(){
for(int i = 1; i <= m; i++){
for(int j = i + 1; j <= m; j++){
if(x[i] == x[j] || y[i] == y[j]) return 0;
}
}
return 1;
}
bool vis[10][10];
void dfs(int nx, int ny, int now, int id){
if(flag) return ;
if(now > n * n) return ;
if(now > 1){
if(check()){
flag = 1;
return ;
}
// return ;
}
vis[nx][ny] = 1;
for(int i = 1; i <= 4; i++){
int dx = nx + fx[i];
int dy = ny + fy[i];
if(dx < 1 || dy < 1 || dx > n || dy > n || a[dx][dy] || vis[dx][dy]) continue ;
x[id] = dx, y[id] = dy;
dfs(dx, dy, now + 1, id);
x[id] -= fx[i]; y[id] -= fy[i];
}
return ;
}
int main(){
// freopen("hh.txt", "r", stdin);
int T; read(T);
while(T--){
memset(vis, 0, sizeof(vis));
memset(a, 0, sizeof(a));
read(n), read(m);
for(int i = 1; i <= m; i++){
read(x[i]), read(y[i]);
a[x[i]][y[i]] = 1;
}
flag = 0;
for(int i = 1; i <= m; i++){
dfs(x[i], y[i], 1, i);
if(flag) break;
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
B. Death's Blessing
首先,对于数组 \(a\), 我们是躲不掉的。因此直接把 \(a\) 全部加上先,然后不管他了。
然后,发现,当 \(b\) 中一个数处于数组两端时,只会有一个贡献。处于中间则会有两倍贡献。
再想想,\(b\) 中的所有数也是不可避免的,除了最后一个。因此,保留最大的那个数到最后一个删,剩下的数都留到两侧删即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#define ll long long
template <class T>
inline void read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
a = x * s;
return ;
}
int a[N], b[N];
ll ans = 0;
struct point{
int id;
int w;
} ;
priority_queue <int, vector<int>, greater<int> > q;
map <int, int> g;
int main(){
// freopen("hh.txt", "r", stdin);
int T; read(T);
while(T--){
while(!q.empty()) q.pop();
ans = 0;
int n; read(n);
for(int i = 1; i <= n; i++){
read(a[i]);
}
for(int i = 1; i <= n; i++){
read(b[i]);
}
for(int i = 1; i <= n; i++) ans += a[i];
int l = 1, r = n; // 目前最靠边的两个 boss
while(l < r){
if(b[l] < b[r]){
ans += b[l];
l++;
}
else{
ans += b[r];
r--;
}
}
cout << ans << endl;
}
return 0;
}
C. Number Game
先推个柿子 \(a + k - i + 1 \ge k - (i + 1) + 1 -> a > -1\)
所以,对于 \(Bob\), 他选择任何一个数都可以让其变为非法。
对于 \(Alice\), 发现她会优先选最大的删,因为 \(k - i + 1\) 会不断缩小。这时,如果 \(Bob\) 选择小的数字,就可以断 \(Alice\) 后路,从两侧缩小 \(Alice\) 的区间。选大数显然不优。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#define ll long long
template <class T>
inline void read(T& a){
T x = 0, s = 1;
char c = getchar();
while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
a = x * s;
return ;
}
int n;
int a[N];
priority_queue <int> q;
int main(){
// freopen("hh.txt", "r", stdin);
int T; read(T);
while(T--){
read(n);
for(int i = 1; i <= n; i++) read(a[i]);
int ans = 0;
sort(a + 1, a + n + 1);
for(int k = n; k >= 0; k--){
bool flag = 1;
int l = 1, r = n;
for(int i = 1; i <= k; i++){
while(a[r] > k - i + 1 && r >= 1) r--;
if(r < l){
flag = 0;
break;
}
r--;
l++;
}
if(flag){
ans = k;
break;
}
}
cout << ans << endl;
}
return 0;
}