• 【BZOJ2876】【Noi2012】骑行川藏 拉格朗日乘法


    题目描述

      给你 (n,E,s_i,k_i,v_i'),要求在

    [sum_{i=1}^nk_i{(v_i-v_i')}^2s_ileq E ]

    的前提下最小化

    [sum_{i=1}^nfrac{s_i}{v_i} ]

      (nleq 10000,0leq Eleq {10}^8,0<s_ileq {10}^5,0<kleq 1,-100<v_i'<100)

    题解

      显然最优解会把体力浪完,所以约束的不等号可以换成等号。

      这样就变成了:在 (G(V)=sum_{i=1}^nk_i{(v_i-v_i')}^2s_i-E=0) 的前提下最小化 (F(V)=sum_{i=1}^nfrac{s_i}{v_i})

      运用拉格朗日乘法,有:

    [egin{cases} sum_{i=1}^nk_i{(v_i-v_i')}^2s_i-E=0\ frac{s_i}{x_i^2}=2lambda k_is_i(x_i-v_i) end{cases} ]

      每个方程左边都是一个在第一象限的双曲线,右边是一条直线。

      所以一定有一个交点,且 (lambda>0)

      可以看出,当 (lambda) 增大时,(v_i) 会减小,(G) 也会减小,所以 (G)(lambda) 递减。

      所以我们只需要二分 (lambda),再二分 (v_i),判断 (G) 的负号即可。

      时间复杂度:(的二分次数的二分次数O(n imes lambda ext{的二分次数} imes v_i ext{的二分次数}))

      二分上界我也不会算,就随便输了一个({10}^{10})

      这题精度要求比较高,(eps)要设为({10}^{-14})

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<cmath>
    #include<functional>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> pll;
    void sort(int &a,int &b)
    {
    	if(a>b)
    		swap(a,b);
    }
    void open(const char *s)
    {
    #ifndef ONLINE_JUDGE
    	char str[100];
    	sprintf(str,"%s.in",s);
    	freopen(str,"r",stdin);
    	sprintf(str,"%s.out",s);
    	freopen(str,"w",stdout);
    #endif
    }
    int rd()
    {
    	int s=0,c,b=0;
    	while(((c=getchar())<'0'||c>'9')&&c!='-');
    	if(c=='-')
    	{
    		c=getchar();
    		b=1;
    	}
    	do
    	{
    		s=s*10+c-'0';
    	}
    	while((c=getchar())>='0'&&c<='9');
    	return b?-s:s;
    }
    void put(int x)
    {
    	if(!x)
    	{
    		putchar('0');
    		return;
    	}
    	static int c[20];
    	int t=0;
    	while(x)
    	{
    		c[++t]=x%10;
    		x/=10;
    	}
    	while(t)
    		putchar(c[t--]+'0');
    }
    int upmin(int &a,int b)
    {
    	if(b<a)
    	{
    		a=b;
    		return 1;
    	}
    	return 0;
    }
    int upmax(int &a,int b)
    {
    	if(b>a)
    	{
    		a=b;
    		return 1;
    	}
    	return 0;
    }
    const double eps=1e-14;
    int n;
    double a[10010],k[10010],s[10010],v[10010];
    double E;
    void getv(double x)
    {
    	for(int i=1;i<=n;i++)
    	{
    		double l=0,r=1e10;
    		while(r-l>eps)
    		{
    			double mid=(l+r)/2;
    			double s1=s[i]/mid/mid;
    			double s2=2*x*k[i]*s[i]*(mid-a[i]);
    			if(s1>s2)
    				l=mid;
    			else
    				r=mid;
    		}
    		v[i]=l;
    	}
    }
    double calc(double x)
    {
    	getv(x);
    	double ans=0;
    	for(int i=1;i<=n;i++)
    		ans+=k[i]*s[i]*(v[i]-a[i])*(v[i]-a[i]);
    	return ans;
    }
    int main()
    {
    	open("bzoj2876");
    	scanf("%d%lf",&n,&E);
    	for(int i=1;i<=n;i++)
    		scanf("%lf%lf%lf",&s[i],&k[i],&a[i]);
    	double l=0,r=1e10;
    	while(r-l>eps)
    	{
    		double mid=(l+r)/2;
    		if(calc(mid)>E)
    			l=mid;
    		else
    			r=mid;
    	}
    	getv(l);
    	double ans=0;
    	for(int i=1;i<=n;i++)
    		ans+=s[i]/v[i];
    	printf("%.10lf
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Python Web学习笔记之Python多线程基础
    Python入门之python可变对象与不可变对象
    Python Web学习笔记之SOCK_STREAM和SOCK_DGRAM
    background和background-position相关笔记
    自定义switch开关
    获取浏览器类型和版本号
    随机生成字符串
    white-space详解
    文件选择按钮随笔
    mouse的各种事件
  • 原文地址:https://www.cnblogs.com/ywwyww/p/9073654.html
Copyright © 2020-2023  润新知