- 题目链接:HDU 5734
- 题意:有一个向量:
W=(w1,w2,...,wn)
,求一个数
α(α≥0)
和一个
B=(b1,b2,...,bn)
向量,使得
∥W−αB∥2
的值最小。
注: ∥X∥=x21+⋯+x2n−−−−−−−−−−−√ ,其中 X=(x1,x2,...,xn) ,其实就是向量的模长。 - 题解:
官方题解:
展开式子可以得到:|W−αB|2=α2∑i=1nb2i−2α∑i=1nwibi+∑i=1nw2i
由于 bi∈+1,−1 那么 ∑i=1nb2i=n , 显然 c=∑i=1nw2i 也是常数. 转化成求 α2n−2α∑i=1nwibi+c 的最小值.
对于固定的 α≥0 , 只要 ∑i=1nwibi 最大就好了. 显然 bi=sign(wi) (符号函数)的时候, ∑i=1nwibi=∑i=1n|wi| 最大.
进一步的, 上面显然是一个关于\alphaα的二次方程, 于是当 α=1n∑i=1nwibi=1n∑i=1n|wi| 时, 取到最大值.
化简下, 可以得到最小值是 ∑ni=1w2i−1n(∑i=1n|wi|)2 .
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX=100000+10;
int a[MAX];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
LL sum1=0,sum2=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum1+=1ll*a[i]*a[i];
sum2=sum2+abs(a[i]);
}
LL gcd=__gcd(sum2*sum2,(LL)n);
cout<<sum1*n/gcd-sum2*sum2/gcd<<"/"<<n/gcd<<endl;
}
return 0;
}