专栏文章

AT_abc400_g [ABC400G] Patisserie ABC 3 题解

AT_abc400_g题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mipoyz2g
此快照首次捕获于
2025/12/03 15:34
3 个月前
此快照最后确认于
2025/12/03 15:34
3 个月前
查看原文
调的有点久。
如果不考虑 kk 的限制,那么有一个显然的 DP:先把 x,y,zx,y,z 的贡献拆掉,转化成选一些数两两配对,计算他们 xix_i 的贡献;再选另外一些数配对,计算他们 yiy_i 的贡献;对 ziz_i 同理。
又由于他们可以任意配对,所以限制就可以直接写成:
从序列中选出三组数,其中每一组的数量都是偶数。答案是第一组的 xix_i 之和加上第二组的 yiy_i 之和加上第三组的 ziz_i 之和。
这样是对的,因为错解一定是不优的。
DP 的时候直接多记一维状态 0S<230 \le S < 2^3 表示三组数个数的奇偶性即可。单次时间复杂度 O(n)O(n)
现在加上 kk 的限制。我们发现选 kk 组的答案关于 kk 是凸的(理解一下就是一定会先选出贡献大的数对,斜率是不增的)。直接上 wqs 二分就行。
写的时候注意一下二分的是 xxx+2x+2 之间的斜率,要进行一些乘除 22 的处理,具体看代码吧。
CPP
#include<bits/stdc++.h>
inline void rd(){}
template<typename T,typename ...U>
inline void rd(T &x,U &...args){
    int ch=getchar();
    T f=1;x=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x*=f;rd(args...);
}
const int N=1e5+5;
typedef long long ll;
const ll INF=1e18;
int T,n,k,v[N][3];
std::pair<ll,int> dp[N][8];
inline std::pair<ll,int> Solve(int x){
	for(int i=0;i<8;i++)dp[0][i]={-INF,0};
	dp[0][0]={0,0};
	for(int i=1;i<=n;i++){
		for(int j=0;j<8;j++){
			dp[i][j]=dp[i-1][j];
			for(int k=0;k<3;k++){
				auto tmp=std::make_pair(dp[i-1][j^(1<<k)].first+2*v[i][k]-x,dp[i-1][j^(1<<k)].second+1);
				dp[i][j]=std::max(dp[i][j],tmp);
			}
		}
	}return dp[n][0];
}
inline void Solve(){
	rd(n,k);
	for(int i=1;i<=n;i++)rd(v[i][0],v[i][1],v[i][2]);
	int L=0,R=2e9;
	while(L<=R){
		int mid=(0ll+L+R)>>1;
		Solve(mid);
		if(dp[n][0].second>=2*k)L=mid+1;
		else R=mid-1;
	}
	Solve(R);
	printf("%lld\n",dp[n][0].first/2+1ll*k*R);
}
signed main(){
	rd(T);
	while(T--)Solve();
    return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...