【BZOJ】【P2876】【NOI2012】【骑行川藏】【题解】【拉格朗日乘数】

传送门:www.lydsy.com:808/JudgeOnline/problem.php?id=2876

题解传送门:www.cppblog.com/prime56/archive/2012/08/13/187087.aspx

kAc神犇讲的东西,真心好用……



二分t,牛顿迭代解vi,与E比较大小,完了

明天就是noi2014了,祝我的学长以及faebdc&&Lavender怒拿Au


Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const double eps=1e-12;
int n;
double ans=1e100;
double E,s[maxn],k[maxn],vi[maxn],v[maxn],t;
double fv(int i,double v){
	return 2.0*k[i]*(vi[i]-v)*v*v*t-1.0;
}
double fvd(int i,double v){
	return -6.0*t*k[i]*v*v+4.0*t*k[i]*vi[i]*v;
}
double calc(int i){
	int n=25;
	double ans=10;
	while(n--)ans-=fv(i,ans)/fvd(i,ans);
	return ans;
}
bool ok(){
	for(int i=1;i<=n;i++)
		v[i]=calc(i);
	double sum=0;
	for(int i=1;i<=n;i++)sum+=s[i]*k[i]*(vi[i]-v[i])*(vi[i]-v[i]);
	if(sum>E)
		return true;
	else 
		return false;
}
int main(){
	scanf("%d%lf",&n,&E);
	for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&s[i],&k[i],&vi[i]);
	//Min -> f(vi)=\sum_{i} si/vi
	//g(vi)=\sum_{i} si*ki*(vi-vi')^2 -E = 0
	//h(vi,t)= f(vi)+t*g(vi)
	//h_vi'(vi,t)=-si*vi^-2 + 2tsi*ki*vi - 2tsi*ki*vi' = 0
	//		     => -1 + 2tki*vi^3 - 2tki*vi'*vi^2 =0
	//           => 2ki(vi'-vi)vi^2 * t -1 =0
 	// t->upper vi->lower T->upper
	//lower_bound t  => calc vi  
	double l=-1,r=0;
	for(int i=80;i;i--){
		t=(l+r)/2.0;
		if(ok())		
			r=t;
		else
			l=t;
	}
	double ans=0;
	for(int i=1;i<=n;i++)ans+=s[i]/v[i];
	cout<<fixed<<setprecision(12)<<ans<<endl;
	return 0;
}


你可能感兴趣的:(bzoj,省选)