比赛链接:https://zhixincode.com/contest/17
A 夺宝奇兵
题解:因为是先从1->n再从n->1,所以我们可以考虑当成一遍走,即每次的选择无非 [ a i → a i + 1 , b i → b i + 1 ] 或 者 [ a i → b i + 1 , b i → a i + 1 ] [a_i\rightarrow a_{i+1},b_i\rightarrow b_{i+1}]或者[a_i\rightarrow b_{i+1},b_i\rightarrow a_{i+1}] [ai→ai+1,bi→bi+1]或者[ai→bi+1,bi→ai+1]。然后取 m i n min min再加上 d i s ( a n , b n ) dis(a_n,b_n) dis(an,bn)即可。
#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 小小马
题解:对于 3 × 4 3 \times4 3×4以上的矩阵,我们可以知道是可以到达任意一个点的。然后我们判断起点和终点的颜色即可,因为每次移动点的颜色是黑白交替的。然后小矩阵窝采用的是爆搜,虽然特判一下也可以。
#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;
}
置置置换
题解:考虑第
i
i
i个数的排列末尾位置为
j
j
j的方案数。
如果
j
j
j为奇数
d
p
[
i
]
[
j
]
=
∑
k
=
1
j
−
1
d
p
[
i
−
1
]
[
k
]
dp[i][j] = \sum_{k = 1}^{j -1}dp[i - 1][k]
dp[i][j]=k=1∑j−1dp[i−1][k]
如果
j
j
j为偶数,我们可以考虑将前面比
j
j
j大的数都加一,这样就有
d
p
[
i
]
[
j
]
=
∑
k
=
j
i
−
1
d
p
[
i
−
1
]
[
k
]
dp[i][j] = \sum_{k = j}^{i-1}dp[i -1][k]
dp[i][j]=k=j∑i−1dp[i−1][k]
这样做是
O
(
N
3
)
O(N^3)
O(N3),但是我们发现每次都是从
i
−
1
i-1
i−1转移过来,所以可以前缀和优化一下。
#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 咆咆咆哮
题解:因为 a a a至少总体攻击力增加,而 b b b是对在场所有单体加成,因次最优方案必定是把所有 a a a上完,再释放 b b b。所以我们可以考虑贪心枚举 a a a的个数。但是怎么贪心呢?假设我们当前选了 i i i个 b b b,那么我们将其中第 j j j个卡片换成 a a a,所获得的收益是 + a [ j ] − b [ j ] ⋅ i +a[j] - b[j] \cdot i +a[j]−b[j]⋅i,因此我们可以以此来排序从而优先选择收益大的 a a a。
#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;
}