CF Round #446 改题

在机房vp了一番div1,就做了一个题, 于是这篇文章就用来改题了。
链接:Here

A

题目:给定一个数列$a$,共$n$项,求最多修改一项的值(必须修改成整数)之后数列中最长严格上升子段的最大长度。

显然,修改比不修改要优,起码不会劣于原来的答案。
那么枚举修改哪一项,向两边延申,这部分可以用前缀/后缀和来解决。
注意细节,就做完了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* @Author: Mingyu Li
* @Date: 2019-03-26T17:39:28+08:00
* @Last modified by: Mingyu Li
* @Last modified time: 2019-03-26T17:42:17+08:00
*/
#include <bits/stdc++.h>
#define Go(i , x , y) for(register int i = x; i <= y; i++)
#define God(i , y , x) for(register int i = y; i >= x; i--)

const int N = 100000 + 5;
int n , a[N];
int pre[N] , suf[N];
int main() {
scanf("%d" , &n);
Go(i , 1 , n) scanf("%d" , &a[i]);

Go(i , 1 , n) pre[i] = a[i] > a[i - 1] ? pre[i-1] + 1 : 1;
God(i , n , 1) suf[i] = (a[i] < a[i + 1]) ? suf[i + 1] + 1 : 1;

int max = std::min(2 , n);
Go(i , 1 , n) { // for each ai
max = std::max(max , pre[i - 1] + 1);
max = std::max(max , suf[i + 1] + 1);
if(a[i + 1] - a[i - 1] <= 1 && i != n && i != 1) continue;
if(i == n) max = std::max(max , pre[i - 1] + 1);
else if(i == 1) max = std::max(max , suf[i + 1] + 1);
else max = std::max(max , pre[i - 1] + suf[i + 1] + 1);
}
std::cout << max << std::endl;
return 0;
}

B

题目:给定$n\times m$的矩阵,每次可以将一行或一列所有数$-p$,代价是没减之前一行/一列的和。要求做k次,求最大代价

解法比较有意思。
考虑只能每次消一行/一列怎么做$\rightarrow$是可以愉快的优先队列贪心的。
那本质上如果限制了消$i$次行,那一定消了$k-i$次列。答案就是$ansrow[i] + anscol[i] + ?$

$ansrow$和$anscol$都比较好算,重点在于$?$是什么。不难发现,这部分其实就是行列相交的部分,这部分$p$都没有被算上,所以$?=i(k-i)p$.

然后暴力枚举i,就做完了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* @Author: Mingyu Li
* @Date: 2019-03-27T18:56:35+08:00
* @Last modified by: Mingyu Li
* @Last modified time: 2019-03-27T20:03:55+08:00
*/
#include <bits/stdc++.h>
#define int long long
#define Go(i , x , y) for(register int i = x; i <= y; i++)
#define God(i , y , x) for(register int i = y; i >= x; i--)

const int N = 1000 + 10;
int n , m , a[N][N] , k , p , ansrow[N*N] , anscol[N*N];
std::priority_queue <int> q1;
signed main() {
scanf("%I64d%I64d%I64d%I64d" , &n , &m , &k , &p);
Go(i , 1 , n) Go(j , 1 , m) scanf("%I64d" , &a[i][j]);

Go(i , 1 , n) {
int sum = 0;
Go(j , 1 , m) sum += a[i][j];
q1.push(sum);
}

Go(i , 1 , k) {
int x = q1.top(); q1.pop();
ansrow[i] = ansrow[i - 1] + x;
q1.push(x - m * p);
}


while(!q1.empty()) q1.pop();

Go(j , 1 , m) {
int sum = 0;
Go(i , 1 , n) sum += a[i][j];
q1.push(sum);
}

Go(i , 1 , k) {
int x = q1.top(); q1.pop();
anscol[i] = anscol[i - 1] + x;
q1.push(x - n * p);
}

int ans = LLONG_MIN;
Go(i , 0 , k) {
int a = i , b = k - i;
int total = a * b * p;
ans = std::max(ans , ansrow[i] + anscol[k - i] - total);
}
std::cout << ans << std::endl;
return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×