ABC218H Red and Blue Lamps
ABC218H Red and Blue Lamps
题意
对\(N\)个位置染色,如果\(A_i\)和\(A_{i+1}\)不同色,则获得\(a_i\) ,要求涂\(r\)个红色,\(n-r\)个蓝色
\[N \leq 2e5
\]
分析
显然会选择贪心地涂间隔\(r\)个颜色\(r \leq n /2\)
问题转化为从\(n\)个物品中选取\(r\)个不相邻物品使得总价值最大
直接朴素的令\(dp[i][j]\)表示前\(i\)个物品选择\(j\)个的做法复杂度很难下降
WQS二分可以把这样的问题转化为任意选择物品个数下的最大价值
令\(g(x)\)表示选择\(x\)个物品的最大价值,显然这是一个凸函数 ,凸函数的性质就是切线斜率具有单调性。
1.二分斜率
对这个凸包的斜率进行二分,如果能通过二分得到点\(x\),就可以比较\(x\)和已知的限制\(r\)来偏移二分的区间
2.计算截距
对于一个固定的斜率,想要寻找和它切的点,只需要找到和\(y\)轴截距最大的点(画个图可以明白)
亦即\(f(x)= g(x) - kx\) 只需要求出\(f_{max}\)即可,考察这个函数的意义:就是每选择一个物品,总价值减\(k\) 下的最大价值,这个东西就是个简单DP
这样就能记录取到\(f_{max}\)时的\(x\)
3. 把二分得到的值再把斜率加回去
然后就做完了,注意实数
代码
#include<bits/stdc++.h>
#define pii pair<long long,long long>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
inline ll rd(){
ll x;
scanf("%lld",&x);
return x;
}
/*
inline int rd(){
int x = 0;
char ch = getchar();
while(ch < '0' || ch > '9') {
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}*/
const int MOD = 23333333;
inline int mul(int a,int b){
int res = (ll)a * b % MOD;
if(res < 0) res += MOD;
return res;
}
inline void add(int &a,int b){
a += b;
if(a >= MOD) a -= MOD;
}
inline void sub(int &a,int b){
a -= b;
if(a < 0) a += MOD;
}
ll gcd(ll a,ll b){
return !b ? a : gcd(b,a % b);
}
const int maxn = 2e5 + 5;
int n,r;
int a[maxn];
pair<long double,int> dp[maxn][2];
pair<long double,int> check(long double v){
dp[n + 1][0] = dp[n + 1][1] = make_pair(0,0);
for(int i = n;i >= 1;i--){
for(int j = 0;j < 2;j++){
auto r0 = dp[i + 1][0],r1 = dp[i + 1][1];
if(!j) r1.fi += a[i];
else r0.fi += a[i];
dp[i][j] = max(r0,r1);
if(!j)
dp[i][j].se++,dp[i][j].fi -= v;
}
}
return max(dp[1][0],dp[1][1]);
}
int main(){
n = rd();
r = rd();
for(int i = 1;i <= n - 1;i++)
a[i] = rd();
long double L = -1e15,R = 1e15;
for(int i = 0;i < 100;i++){
long double mid = (L + R) / 2.0;
auto it = check(mid);
if(it.se < r) R = mid;
else L = mid;
}
auto it = check(L);
ll ans = (ll)(it.fi + r * L);
printf("%lld",ans);
}