比赛链接:https://zhixincode.com/contest/17
A 夺宝奇兵
题解:因为是先从1->n再从n->1,所以我们可以考虑当成一遍走,即每次的选择无非 。然后取 再加上 即可。
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 100100;
struct node{
int x,y;
}a[N],b[N];
int dis(node u,node v)
{
return abs(u.x - v.x) + abs(u.y - v.y);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n,m;
cin >> n >> m;
long long ans = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d %d %d %d",&a[i].x,&a[i].y,&b[i].x,&b[i].y);
if(i == 1) continue;
ans += min(dis(a[i - 1], a[i]) + dis(b[i - 1], b[i]), dis(a[i - 1], b[i]) + dis(b[i - 1], a[i]));
}
cout << ans + dis(a[n],b[n]) << endl;
return 0;
}
C 最小边覆盖
题解:易发现对于每一条边,两点的度都大于1,那么这条边就是多余的。
#include<bits/stdc++.h>
using namespace std;
const int N = 3E5+10;
int cnt[N], u[N],v[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n,m;
cin >> n >> m;
for(int i = 0; i < m; ++i) {
scanf("%d %d",&u[i],&v[i]);
cnt[u[i]]++;
cnt[v[i]]++;
}
for(int i = 0; i < m; ++i) {
if(cnt[u[i]] > 1 && cnt[v[i]] > 1) {
return puts("No"),0;
}
}
puts("Yes");
return 0;
}
F 小小马
题解:对于 以上的矩阵,我们可以知道是可以到达任意一个点的。然后我们判断起点和终点的颜色即可,因为每次移动点的颜色是黑白交替的。然后小矩阵窝采用的是爆搜,虽然特判一下也可以。
#include<bits/stdc++.h>
using namespace std;
int dir[8][2] = {-2,-1, -2,1, -1,-2, -1,2, 1,-2, 1,2, 2,-1, 2,1};
bool vis[11][11];
int n,m,sx,sy,ex,ey,rec;
bool isWhite(int x,int y)
{
return (x & 1) == (y & 1);
}
void dfs(int x,int y,int white,int black)
{
if(x == ex && y == ey) {
if(white == black) {
rec = 1;
return;
}
}
for(int i = 0; i < 8; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx < 1 || tx > n || ty > m || ty < 1 || vis[tx][ty])
continue;
vis[tx][ty] = 1;
if(isWhite(tx,ty)) white++;
else black++;
dfs(tx,ty,white,black);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
cin >> n >> m >> sx >> sy >> ex >> ey;
if (n >= 3 && m >= 3) {
if ((sx == 2 && sy == 2) || (ex == 2 && sy == 2)) {
puts("No");
return 0;
}
if (isWhite(sx, sy) == isWhite(ex, ey))
puts("No");
else
puts("Yes");
} else {
if(n == 2) {
int k1 = abs(sy - ey);
if(abs(sx - ex) == 1 && k1 % 2 == 0 && k1 % 4 != 0) {
puts("Yes");
}else{
puts("No");
}
return 0;
}else if(m == 2){
int k1 = abs(sx - ex);
if(abs(sy - ey) == 1 && k1 % 2 == 0 && k1 % 4 != 0) {
puts("Yes");
}else{
puts("No");
}
return 0;
}
int white = 0, black = 0;
if (isWhite(sx, sy)) white++;
else black++;
dfs(sx, sy, white, black);
puts(rec ? "Yes" : "No");
}
return 0;
}
置置置换
题解:考虑第
个数的排列末尾位置为
的方案数。
如果
为奇数
如果
为偶数,我们可以考虑将前面比
大的数都加一,这样就有
这样做是
,但是我们发现每次都是从
转移过来,所以可以前缀和优化一下。
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
long long dp[1010][1010];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n;
cin >> n;
dp[1][1] = 1;
for(int i = 2; i <= n; ++i) {
for(int j = 1; j <= i; ++j) {
if(i & 1) {
dp[i][j] = (dp[i][j - 1] + dp[i - 1][j - 1]) % mod;
}else{
dp[i][j] = (dp[i][j - 1] + dp[i - 1][i - 1] - dp[i - 1][j - 1] + mod) % mod;
}
}
}
cout << dp[n][n] << endl;
return 0;
}
I 咆咆咆哮
题解:因为 至少总体攻击力增加,而 是对在场所有单体加成,因次最优方案必定是把所有 上完,再释放 。所以我们可以考虑贪心枚举 的个数。但是怎么贪心呢?假设我们当前选了 个 ,那么我们将其中第 个卡片换成 ,所获得的收益是 ,因此我们可以以此来排序从而优先选择收益大的 。
#include<bits/stdc++.h>
using namespace std;
struct node{
int a,b;
long long c;
bool operator < (const node & u) const {
return c > u.c;
}
}f[1010];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n;
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> f[i].a >> f[i].b;
}
long long ans = 0, sum = 0;
for(int i = 1; i <= n; ++i) {
sum = 0;
for(int j = 1; j <= n; ++j) {
f[j].c = f[j].a - f[j].b * i;
}
sort(f + 1, f + n + 1);
for(int j = 1; j <= i; ++j) {
sum += f[j].a;
}
for(int j = i + 1; j <= n; ++j) {
sum += f[j].b * i;
}
ans = max(ans, sum);
}
cout << ans << endl;
return 0;
}