• 拉格朗日乘数法 学习小记


    前言

    本来准备看日报很久了,但是一直没有看懂,今天才恍然大悟。特此,记之。

    拉格朗日乘数法

    对于一个多元函数 (F(x,y,z,..)),我们假如我们需要满足 (varphi(x,y,z,...)=0),那么我们想要求出这个函数的最值,我们就可以使用拉格朗日乘数法,具体来说,我们可以我们就是要让:

    [F(x,y,z,...)+lambda varphi(x,y,z,...) ]

    是个极值。举个例子,如果我们要让这个玩意最小,那么,在 (lambda) 为某种取值的时候,我们肯定会使 (varphi(x,y,z,...))(0)。最大值相似。

    考虑这个玩意怎么求极值,可以发现其实就是在求导之后为 (0) 的点就是极值,整体求导说白了就是每个变量求偏导,你只需要让这个东西为 (0) 即可。

    一些题目

    [NOI2012]骑行川藏

    题目传送门

    思路

    不难看出题目就是这样一个意思:

    [sum_{i=1}^{n} k_i(v_i-v_i^{'})^2_i=E_u ]

    [sum_{i=1}^{n} frac{s_i}{v_i} ]

    最小。

    不难看出就是:

    [F(v_1,v_2,...,v_n)=sum_{i=1}^{n} frac{s_i}{v_i},varphi(v_1,v_2,...,v_n)=sum_{i=1}^{n} k_i(v_i-v_i^{'})^2s_i-E_u ]

    直接套版子就可以得到:

    [left{egin{array}{l} 2lambda k_iv_i^2(v_i-v_i^{'})=1\ sum_{i=1}^{n} k_i(v_i-v_i^{'})^2s_i=E_u end{array} ight.]

    可以直接二分 (lambda) ,然后在内部二分 (v_i) 判断即可。

    时间复杂度 (Theta(nlog^2w)),其中 (w) 是值域。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define double long double
    #define Int register int
    #define MAXN 10005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n;
    double Eu,k[MAXN],s[MAXN],v[MAXN],v1[MAXN];
    
    bool check (double lamb){
    	double res = 0;
    	for (Int i = 1;i <= n;++ i){
    		double l = max ((double)0,v1[i]),r = 1e5;
    		while (r - l > 1e-12){
    			double mid = (l + r) * 0.5;
    			if (2 * lamb * k[i] * mid * mid * (mid - v1[i]) <= 1) l = mid;
    			else r = mid;
    		}
    		v[i] = r,res += k[i] * (r - v1[i]) * (r - v1[i]) * s[i];
    	}
    	return res <= Eu;
    }
    
    signed main(){
    	read (n),scanf ("%Lf",&Eu);
    	for (Int i = 1;i <= n;++ i) scanf ("%Lf%Lf%Lf",&s[i],&k[i],&v1[i]);
    	double l = 0,r = 1e5;
    	while (r - l > 1e-12){
    		double mid = (l + r) * 0.5;
    		if (check (mid)) r = mid;
    		else l = mid;
    	}
    	double res = 0;
    	for (Int i = 1;i <= n;++ i) res += s[i] * 1.0 / v[i];
    	printf ("%.9Lf
    ",res);
    	return 0;
    }
    

    CF1344D Résumé Review

    题目传送门

    思路

    跟上面一个类似,不过不是那么板了。

    不难发现我们可以按 (a_i) 排序,然后对于一个 (lambda),有 (b_i=sqrt{(a_i-lambda)/3})

    但是因为 (b_ile a_i) 的限制,而且 (sum_{i=1}^{n} b_i=k),所以我们并不能这样搞。但是我们排序后,我们不满足条件 (b_i> a_i) 的一定是前面一段(因为是个凹函数),所以我们可以二分一下前面多少个为 (a_i)。然后我们只需要判断 (sum b_i) 是否 (ge k)

    但是并没有完,我们显然 (b_i) 要下取整,而且我们还并不能完全保证 (sum b_i=k),所以我们可以把一些 (b_i) 增大,可以保证的是,一个数最多会增大 (1),至于选哪些直接贪心看选哪些贡献最大就好了。

    时间复杂度 (Theta(nlog^2 w))

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define double long double
    #define Int register int
    #define int long long
    #define MAXN 100005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    double b[MAXN];
    int n,k,a[MAXN],ansf[MAXN],index[MAXN];
    
    struct node{
    	int ind,v;
    	bool operator < (const node &p)const{return v < p.v;}
    }c[MAXN];
    
    bool check (int x){
    	double l = -1e20,r = 1e20,tot = 0,mid;int k1 = k;bool flg = 0;
    	for (Int i = 1;i <= x;++ i) k1 -= a[i];
    	for (Int i = x + 1;i <= n;++ i) l = max (l,(double)a[i] - 3 * a[i] * a[i]),r = min (r,(double)a[i]);
    	while (r - l > 1){
    		mid = (l + r) * 0.5,tot = 0;
    		for (Int i = x + 1;i <= n;++ i) b[i] = sqrt ((a[i] - mid) / 3),tot += b[i];
    		if (tot >= k1) l = mid,flg = 1;
    		else r = mid;
    	}
    	for (Int i = x + 1;i <= n;++ i) b[i] = sqrt ((a[i] - l) / 3);
    	return flg;
    }
    
    signed main(){
    	read (n,k);
    	for (Int i = 1;i <= n;++ i) read (c[i].v),c[i].ind = i;
    	sort (c + 1,c + n + 1);for (Int i = 1;i <= n;++ i) a[i] = c[i].v,index[i] = c[i].ind;
    	int l = 0,r = n,ans = 0;
    	while (l <= r){
    		int mid = (l + r) >> 1;
    		if (check (mid)) r = mid - 1,ans = mid;
    		else l = mid + 1;
    	}
    	for (Int i = 1;i <= ans;++ i) b[i] = a[i];check (ans);
    	for (Int i = 1;i <= n;++ i) b[i] = floor (b[i]),k -= b[i];
    	int tot = 0;for (Int i = 1;i <= n;++ i) if (b[i] < a[i]) c[++ tot] = node {i,a[i] - 3 * b[i] - 3 * b[i] * b[i]};
    	sort (c + 1,c + tot + 1),reverse (c + 1,c + tot + 1);
    	for (Int i = 1;i <= tot && i <= k;++ i) b[c[i].ind] ++;
    	for (Int i = 1;i <= n;++ i) ansf[index[i]] = b[i];
    	for (Int i = 1;i <= n;++ i) write (ansf[i]),putchar (' ');
    	putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    关于无法使用xx-pc附加到应用程序iisexpress.exe
    iis 7.5 0x80004005 静态文件 html、js、css 500错误
    递归删除指定目录下面的所有文件夹和文件
    http请求相关
    常用分页写法
    获取与Url链接相关的信息
    解决iis7 0x80070002 错误代码问题
    实现Cookie跨域共享
    文本框值改变事件
    动态加载、移除、替换JS和CSS
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14044966.html
Copyright © 2020-2023  润新知