关于 WQS 二分的一点疑问
查看原帖
关于 WQS 二分的一点疑问
390742
qwqUwU楼主2023/7/27 19:15

WQS 二分在统计选择数量时是不是最好强制定一个方向。

比如此题,我先放代码:

#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
inline ll read(){
	ll x=0,f=1,c=getchar();
	while(c<'0'||c>'9')f=(c=='-'?-1:1),c=getchar();
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
const int N=1e6+10;
const ll INF=1e12;
int n,m;
ll dp[N],g[N],s[N];
int q[N];
void init(){
	memset(dp,0,sizeof(dp));
	memset(g,0,sizeof(g));
}
ll k;
#define b(i) (dp[i]+s[i]*s[i])
ld slope(int i,int j){
	return s[i]==s[j]?1.0*(b(j)-b(i))*INF:1.0*(b(j)-b(i))/(s[j]-s[i]);
}
void solve(){
	int head=1,tail=0;
	q[++tail]=0;
	for(int i=1;i<=n;i++){
		while(head < tail && slope(q[head],q[head+1]) < (ld)(2.0*s[i]))head++;
		int j=q[head];
		dp[i]=dp[j]+(s[i]-s[j])*(s[i]-s[j])-k;
		g[i]=g[j]+1;
		while(head < tail && slope(q[tail-1],q[tail]) > slope(q[tail],i))tail--;
		q[++tail]=i;
	}
}

int main(){
	//freopen("data.in","r",stdin);
	//	freopen(".out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++)s[i]=read()+s[i-1];
	ll l=-INF,r=0,res=1;
	while(l<=r){
		ll mid=(l+r)/2;
		init();
		k=mid;
		solve();
		if(g[n] <= m)res=mid,l=mid+1;
		else r=mid-1;
	}
	k=res;
	solve();
	//assert(g[n]==m);
	cout<<(m*(dp[n]+k*m) - s[n]*s[n])<<"\n";
	fprintf(stderr,"%lld %lld %lld %lld\n",res,dp[n],s[n],dp[n]+g[n]*k);
	return 0;
}

然后斜率优化那一段是没有加上关于 gg 的判定的,那 gg 出来的是不是一个较为随机的值。

此时 WQS 二分会导致可能二分不到 mm 。

于是那个 assert 就会 RE(我试过第 88 个点)。

那为什么最后还原 dpdp 时用的是 mm 而不是 g(n)g(n) ?

thx.

2023/7/27 19:15
加载中...