BOBERT - Stick values
#C++
第一次好好壓複雜度,然後把題目AC,紀錄一下XD
原題連結
題目
給一個序列 $a_0 \dots a_{N-1}$ ,和 $s$ 個棒子,所有棒子的長度和 = $N$,現在我們要用這些棒子蓋滿序列(棒子長度有多長就可以覆蓋多少數字),每個棒子不能互相覆蓋,不能超出界線,不可多用或少用。
現在定義一個棒子的好棒棒度
是 $L \times(max(a, b)-min(a, b))$ , $L$ 是長度,$max(a, b)$ 和 $min(a, b)$ 被定義為棒子覆蓋到的數字們最大值和最小值。
請輸出好棒棒度總和
的最大值。
過程
第一次
一開始是想對 $s$ 和 $2^s$ 做dp,類似這樣
$$
dp[s+1][sts|2^i] = max(dp[s][sts]+len \times query())
$$
然後從 $dp[1]$ 滾上去。
query用線段樹實做。
複雜度: $O(S^22^S \log S)$
結果:TLE
第二次
仔細想想沒有必要對 $s$ dp,因為每層接觸到的狀態都是Disjoint的。所以改用queue
做。
複雜度:$O(S2^S \log S)$
結果:TLE
第三次
自己先偷偷比對了一下假如query做到 $O(1)$ 的話, $10^5$ 測資似乎會快個 4 倍,所以把query改為sparse table
。
複雜度:$O(S2^S)$
結果:TLE
第四次
因為複雜度基本上已經很ok了,所以開始檢查一些常數可能有點炸了的地方,發現我sparse table
發懶直接用int64
,改一陣。
絕果:AC
Code
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
| #include <cstdio>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long int int64;
typedef vector<int> VI;
typedef vector<VI> VVI;
const int64 INF = 1000000001;
struct maxspt{
VVI maxarr;
maxspt(int n, int64* arr){
int k = (int)log2((double)n+0.2);
maxarr = VVI(n, VI(k+1));
for(int lx = 0;lx < n;lx++) maxarr[lx][0] = arr[lx];
for(int lx = 1;lx <= k;lx++)
for(int ly = 0;ly+(1<<(lx-1)) < n;ly++)
maxarr[ly][lx] = max(maxarr[ly][lx-1], maxarr[ly+(1<<(lx-1))][lx-1]);
return;
}
int query(int a, int b){
int k = (int)(log2(b-a+1.2));
return max(maxarr[a][k], maxarr[b-(1<<k)+1][k]);
}
};
struct minspt{
VVI minarr;
minspt(int n, int64* arr){
int k = (int)log2((double)n+0.2);
minarr = VVI(n, VI(k+1));
for(int lx = 0;lx < n;lx++) minarr[lx][0] = arr[lx];
for(int lx = 1;lx <= k;lx++)
for(int ly = 0;ly+(1<<(lx-1)) < n;ly++)
minarr[ly][lx] = min(minarr[ly][lx-1], minarr[ly+(1<<(lx-1))][lx-1]);
return;
}
int query(int a, int b){
int k = (int)(log2(b-a+1.2));
return min(minarr[a][k], minarr[b-(1<<k)+1][k]);
}
};
int64 dp[1<<20] = {0};
bool vis[1<<20] = {0};
int64 stl[30];
int64 arr[100000];
int main(){
int n, s;
scanf("%d", &n);
for(int lx = 0;lx < n;lx++) scanf("%lld", arr+lx);
maxspt maxtb(n, arr);
minspt mintb(n, arr);
scanf("%d", &s);
for(int lx = 0;lx < s;lx++) scanf("%lld", stl+lx);
queue<int> que;
que.push(0);
while(que.size()){
int sts = que.front(); que.pop();
int64 len = 0; for(int lx = 0;lx < s;lx++) if(sts&(1<<lx)) len += stl[lx];
for(int lx = 0;lx < s;lx++){
if(sts&(1<<lx)) continue;
int nsts = sts|(1<<lx);
if(stl[lx]) dp[nsts] = max(dp[nsts], dp[sts] + ((int64)(maxtb.query(len, len+stl[lx]-1) - mintb.query(len, len+stl[lx]-1)))*stl[lx]);
else dp[nsts] = max(dp[nsts], dp[sts]);
if(!vis[nsts]){
que.push(nsts);
vis[nsts] = 1;
}
}
}
printf("%lld\n", dp[(1<<s)-1]);
return 0;
}
|
NOTE
前後共花了2:15
QAQ