A. Consecutive Sum
题意:
给定长度为 n n n 的数组,如果 i = j ( m o d k ) i=j(modk) i=j(modk) ,可以交换 a i a_i ai 与 a j a_j aj,最多进行 k k k 次操作,求长度为 k k k 的连续序列最大值。
解析:
将数组按照对 k k k取余进行分组,然后取出每一组的最大值
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2+10;
vector<ll> a[maxn];
int n, k;
void solve(){
cin >> n >> k;
for(int i = 0; i <= 100; i++){
a[i].clear();
a[i].push_back(0);
}
for(int i = 1; i <= n; i++){
ll x;
cin >> x;
a[i%k].push_back(x);
}
ll sum = 0;
for(int i = 0; i < k; i++){
sum += *max_element(a[i].begin(), a[i].end());
}
cout << sum << endl;
}
int main(){
int T;
cin >> T;
while(T--)
solve();
return 0;
}
B. Rule of League
题意:
n
n
n的人比赛。
1
1
1与
2
2
2比赛,胜者与
3
3
3比赛,然后胜者与
4
4
4比赛,共
n
−
1
n-1
n−1场比赛。
给定
x
,
y
x,y
x,y,是否存在方案,使所有的胜利场数为
x
x
x或
y
y
y。若存在,给出方案。
解析:
显然 x , y x,y x,y中有且仅有一个零,否则不存在合法方案。不妨 x ≠ 0 , y = 0 x \neq 0,y=0 x=0,y=0。其次, ( n − 1 ) % x = 0 (n-1)\%x = 0 (n−1)%x=0。方案为:第 i i i各人连胜 x x x次,然后第 i + x i+x i+x人连胜 x x x次,特判一下 i = 1 i=1 i=1。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int x, y, n;
void solve(){
cin >> n >> x >> y;
if((x==0&&y==0) || (x!=0&&y!=0)){
cout << -1 << endl;
return;
}
int len = max(x, y);
if((n-1)%len != 0){
cout << -1 << endl;
return;
}
for(int i = 1; i <= n;){
for(int j = 1; j <= len; j++)
cout << i << " ";
if(i == 1)
i++;
i += (len);
}
cout << endl;
return ;
}
int main(){
int T;
cin >> T;
while(T--)
solve();
}
C. Parity Shuffle Sorting
题意:
给定长度为 n n n的数组,每次操作选择 l , r l,r l,r,若 a l + a r a_l+a_r al+ar为偶数,令 a l = a r a_l = a_r al=ar;若 a l + a r a_l+a_r al+ar为奇数,令 a r = a l a_r = a_l ar=al。求方案,使序列不降。
解析:
如果所有数都相同,也是不降序列。首先选择 l = 1 , r = n l=1,r=n l=1,r=n,使 a 1 = = a n a_1 = =a_n a1==an,然后对 a i a_i ai 2 ≤ i ≤ n − 1 2 \le i \le n-1 2≤i≤n−1,选择 a 1 a_1 a1或 a n a_n an。需要 n − 1 n-1 n−1次操作。
代码:
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
int n, t, x, a[100005];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
for(cin >> t; t--;){
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
cout << n - 1 << endl;
if(n > 1)
cout << 1 << ' ' << n << endl;
x = (a[1] + a[n]) % 2 ? a[1] : a[n];
for(int i = 2; i < n; i++){
if((x + a[i]) % 2)
cout << 1 << ' ' << i << endl;
else
cout << i << ' ' << n << endl;
}
}
return 0;
}
D1. Zero-One (Easy Version)
题意:
给定两个长度相同的01串 a , b a,b a,b,每次可以选定一个串的两个位置 l , r l,r l,r,01翻转。如果选择的位置相邻即 l + 1 = r l+1=r l+1=r,则翻转的代价为 x x x;不相邻的翻转的代价为 y y y, ( x ≥ y ) (x \ge y) (x≥y)。询问使两个串相同的最小代价。
解析:
每次能调整两个位置,如果需要调整的位置为奇数,显然不可能,所以需要调整的位置为偶数。
调整一次相邻位置的代价
x
x
x可以用调整两次不相邻位置的代价
2
y
2y
2y代替。
如果需要调整的位置数大于等于4,可以一直花费代价
y
y
y
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
string a, b;
int c[maxn];
int n, x, y;
void solve(){
cin >> n >> x >> y;
cin >> a >> b;
int cnt = 0;
int l = INF, r = -1;
for(int i = 0; i < n; i++){
c[i] = (a[i]==b[i])?0:1;
cnt += c[i];
if(c[i]){
l = min(l, i);
r = max(r, i);
}
}
if(cnt%2 == 1){
cout << -1 << endl;
return;
}
if(l+1 == r)
cout << min(x, 2*y) << endl;
else
cout << cnt/2*y << endl;
return;
}
int main(){
int T;
cin >> T;
while(T--)
solve();
return 0;
}
D2. Zero-One (Hard Version)
题意:
同上,取消条件 x ≥ y x \ge y x≥y,增加条件 n ≤ 5000 n \le 5000 n≤5000
解析:
修改一次相邻位置的代价
x
x
x可以用修改两次不相邻位置的代价
2
y
2y
2y代替。修改一次不相邻位置
(
l
,
r
)
(l,r)
(l,r) 可以用修改
(
r
−
l
)
(r-l)
(r−l)次相邻位置的代价
x
(
r
−
l
)
x(r-l)
x(r−l)代替。
预处理所有修改的位置,然后DP。
d
p
i
j
=
{
d
p
i
+
2
,
j
+
c
o
s
t
(
i
,
i
+
1
)
d
p
i
+
1
,
j
−
1
+
c
o
s
t
(
i
,
j
)
d
p
i
,
j
−
2
+
c
o
s
t
(
j
−
1
,
j
)
dp_{ij}=\left\{ \begin{aligned} dp_{i+2,j}+cost(i,i+1) \\ dp_{i+1, j-1}+cost(i, j) \\ dp_{i, j-2}+cost(j-1, j)\\ \end{aligned} \right.
dpij=⎩
⎨
⎧dpi+2,j+cost(i,i+1)dpi+1,j−1+cost(i,j)dpi,j−2+cost(j−1,j)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e3+10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll x, y, n;
string a, b;
ll dp[maxn][maxn];
vector<int> pos;
ll cost(int l, int r){
if(l+1 == r)
return min(2*y, x);
else
return min(y, x*(r-l));
}
void DP(int x){
for(int i = 0; i <= x; i++)
for(int j = 0; j <= x; j++)
dp[i][j] = 0;
for(int len = 2; len <= x; len++){
for(int l = 0; l+len <= x; l++){
int r = l+len-1;
ll res = INF;
res = min(res, dp[l+2][r]+cost(pos[l], pos[l+1]));
res = min(res, dp[l][r-2]+cost(pos[r-1], pos[r]));
res = min(res, dp[l+1][r-1]+cost(pos[l], pos[r]));
dp[l][r] = res;
}
}
}
void solve(){
cin >> n >> x >> y;
cin >> a >> b;
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
dp[i][j] = -1;
pos.clear();
for(int i = 0; i < n; i++)
if(a[i] != b[i])
pos.push_back(i);
if(pos.size()%2){
cout << -1 << endl;
return;
}
else if(pos.size() == 0){
cout << 0 << endl;
return;
}
else if(pos.size() == 2){
if(pos[0]+1 == pos[1])
cout << min(2*y, x) << endl;
else
cout << min(y, x*(pos[1]-pos[0])) << endl;
}
else if(y <= x)
cout << pos.size()/2*y << endl;
else{
DP(pos.size());
cout << dp[0][pos.size()-1] << endl;
}
}
int main(){
int T;
cin >> T;
while(T--)
solve();
return 0;
}
E. Conveyor
题意:
每个格子上都有一个传送带,初始向右。每秒在 ( 0 , 0 ) (0,0) (0,0)处放一个物品。当传送带传送完一次物品后,传送带的方向发生改变。向右的变为向下,向下的变为向右。询问 t t t 时刻,坐标 ( x , y ) (x,y) (x,y)的传送带上是否有物品。
解析:
求出 t t t秒内,每个传送带经过了多少物品 f ( t , x , y ) f(t, x, y) f(t,x,y),答案为 f ( t , x , y ) − f ( t − 1 , x , y ) f(t,x,y)-f(t-1,x,y) f(t,x,y)−f(t−1,x,y)是否为0。注意,从 ( 0 , 0 ) (0,0) (0,0)到 ( x , y ) (x,y) (x,y)花费 x + y x+y x+y的时间。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200;
int q;
ll dp[maxn][maxn];
ll f(ll t, ll x, ll y){
memset(dp, 0, sizeof(dp));
dp[0][0] = max(t-(x+y)+1, 0ll);
for(int i = 0; i <= x; i++)
for(int j = 0; j <= y; j++){
dp[i+1][j] += dp[i][j]/2;
dp[i][j+1] += dp[i][j]-dp[i][j]/2;
}
return dp[x][y];
}
int main(){
cin >> q;
for(int i = 1; i <= q; i++){
ll t, x, y;
cin >> t >> x >> y;
ll ans = f(t, x, y)-f(t-1, x, y);
if(ans > 0)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
https://zhuanlan.zhihu.com/p/566175996