題目鏈接:點我啊╭(╯^╰)╮
題目大意:
個數字,每個數字爲
每次選取一串數字,得到
爲這一串數字的任意一個, 爲這串數字有 個
求全部選取完之後的最大值
解題思路:
明顯決策點
用前綴計算,設 爲 這個數字是相同數字裏的第幾個
則
複雜度:
但是這道題的決策是倒過來的!!!因此要在隊尾操作!!!
斜率優化
發現有與 和 都相關的項,則提取出來,把只和 有關的項分離出去
設 ,,,得
符號爲 ,維護上凸包,斜率遞減,由於 是遞增,所以在隊尾操作
對於一個 而言, 是單調的,因此不需要二分
時間複雜度:
決策單調
發現平方的增長是很快的
若 的決策點有 和 ,,,
那麼隨着 的增大, 增長的肯定要比 快
因此 可以直接刪掉,滿足決策單調
注意這裏的決策單調是倒序單調的
時間複雜度:
斜率優化:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 1e5 + 5;
int n;
ll s[maxn], a[maxn];
ll num[maxn], dp[maxn];
vector <int> q[maxn];
ll Y(int i){
return dp[i-1] + s[i] * a[i] * a[i] - 2 * s[i] * a[i];
}
ll X(int i){
return a[i];
}
double slope(int i, int j){
return 1.0 * (Y(i) - Y(j)) / (X(i) - X(j));
}
#define sz q[s[i]].size()
#define t1 q[t][sz-1]
#define t2 q[t][sz-2]
ll cal(int i, int j){
return dp[j-1] + s[i] * (a[i] - a[j] + 1) * (a[i] - a[j] + 1);
}
signed main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%lld", s+i);
a[i] = ++num[s[i]];
}
for(int i=1; i<=n; i++){
int t = s[i];
while(sz>1 && slope(t1, i)>=slope(t2, t1)) q[t].pop_back();
q[t].push_back(i);
while(sz>1 && slope(t2, t1)<2*s[i]*a[i]) q[t].pop_back();
// while(sz>1 && cal(i, t1)<=cal(i, t2)) q[t].pop_back();
dp[i] = cal(i, t1);
}
printf("%lld\n", dp[n]);
}
決策單調:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 1e5 + 5;
int n;
ll a[maxn], s[maxn];
ll dp[maxn], num[maxn];
vector <int> q[maxn];
#define sz q[t].size()
#define t1 q[t][sz-1]
#define t2 q[t][sz-2]
ll cal(int i, int j){
return dp[i-1] + 1ll * j * j * s[i];
}
int ck(int i, int j){
int l = max(a[i], a[j]), r = n, mid;
while(l <= r){
mid = l + r >> 1;
if(cal(i, mid-a[i]+1)>=cal(j, mid-a[j]+1)) r = mid - 1;
else l = mid + 1;
}
return l;
}
signed main() {
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%lld", s+i);
a[i] = ++num[s[i]];
}
for(int i=1; i<=n; i++){
int t = s[i];
while(sz>1 && ck(t2, t1)<=ck(t1, i)) q[t].pop_back();
q[t].push_back(i);
while(sz>1 && ck(t2, t1)<=a[i]) q[t].pop_back();
dp[i] = cal(t1, a[i] - a[t1] + 1);
}
printf("%lld\n", dp[n]);
}