暴力dp很简单,现在考虑优化,虽然本题可以选小于等于a,b,但是显然我们不会这么干,肯定用的越多越好
因此变成了选k个问题,这样就可以考虑使用wqs二分来优化,本质上就是我们二分一个附加权值给选择,原先我们是选的越多越优秀,现在的话就成为了一个单峰函数
我们观察这个函数取到极值点的时候选的个数是多少,如果大于所给条件,那么就增加权值,这样就能二分出答案直到刚好。最后算结果的时候把他加回来就好
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+10; const int mod=1e9+7; const int inf=0x3f3f3f3f; double eps=1e-8; double f[N],fa[N],fb[N]; double p[N],q[N]; int n,a,b; void cal(double w1,double w2){ int i; for(i=1;i<=n;i++){ f[i]=f[i-1]; fa[i]=fa[i-1]; fb[i]=fb[i-1]; if(f[i]<f[i-1]+p[i]-w1){ f[i]=f[i-1]+p[i]-w1; fa[i]=fa[i-1]+1; fb[i]=fb[i-1]; } if(f[i]<f[i-1]+q[i]-w2){ f[i]=f[i-1]+q[i]-w2; fa[i]=fa[i-1]; fb[i]=fb[i-1]+1; } if(f[i]<f[i-1]+q[i]+p[i]-q[i]*p[i]-w2-w1){ f[i]=f[i-1]+p[i]+q[i]-q[i]*p[i]-w2-w1; fa[i]=fa[i-1]+1; fb[i]=fb[i-1]+1; } } } int main(){ //ios::sync_with_stdio(false); int i; cin>>n>>a>>b; for(i=1;i<=n;i++){ cin>>p[i]; } for(i=1;i<=n;i++){ cin>>q[i]; } double l1=0,r1=1; double l2,r2; while(l1+eps<=r1){ double mid1=(l1+r1)/2; l2=0,r2=1; while(l2+eps<=r2){ double mid2=(l2+r2)/2; cal(mid1,mid2); if(fb[n]>b) l2=mid2; else r2=mid2; } cal(mid1,r2); if(fa[n]>a){ l1=mid1; } else{ r1=mid1; } } cal(r1,r2); printf("%.6f\n",f[n]+a*r1+b*r2); }View Code