【BZOJ 2711】 2711: [Violet 2]After 17 (0-1 背包)

2711: [Violet 2]After 17

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 224  Solved: 153

Description

Input

Output

Sample Input

4
4 5
1 2
3 3
4 1

Sample Output

-38.00

HINT

Source

【分析】

  虽然是道水题,但是我今天终于自己真正想出来一道了,撒花~~还挤到第7啦~~

  点积的话,就是求$x2*x1+x3*x1+x3*x2+...+xn*x(n-1)+y2*y1+y3*y1+y3*y2+...yn*y(n-1)$

  设$sumx=x1+x2+...+xn, sumy=y1+y2+...yn$

  就是$sumx^2-sum xi^2+sumy^2-sum yi^2$

  $x$和$y$没有半毛钱关系,分开做。

  其实是很显然$(x,y)$是只会选择那角落四个点的【这是套路也是可以证(luan)明(shuo)的,【就是假设把一个$x$增加$a$ 贡献是$2a(x-sumx)$,你总往好的一边增加就好了。

  那么$xi^2+yi^2$也是固定的。

  那么就要$sumx$和$sumy$尽量接近0就好了。

  这个,很熟悉吧?把$dfrac{sum xi}{2}$当成背包容量,把背包尽量填满就行了,这个0-1背包bool就好。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 210
 8 #define LL long long
 9 
10 bool f[Maxn*Maxn];
11 int nx[Maxn],ny[Maxn];
12 
13 int main()
14 {
15     int n,ans=0,h1=0,h2=0;
16     scanf("%d",&n);
17     for(int i=1;i<=n;i++)
18     {
19         int x,y;
20         scanf("%d%d",&x,&y);
21         ans-=x*x+y*y;
22         h1+=x;h2+=y;
23         nx[i]=x;ny[i]=y;
24     }
25     memset(f,0,sizeof(f));
26     f[0]=1;
27     for(int i=1;i<=n;i++)
28     {
29         for(int j=h1/2;j>=nx[i];j--)
30         {
31             f[j]|=f[j-nx[i]];
32         }
33     }
34     int mx=0;
35     for(int i=1;i<=h1/2;i++) if(f[i]) mx=i;
36     ans+=(h1-2*mx)*(h1-2*mx);
37     memset(f,0,sizeof(f));
38     f[0]=1;
39     for(int i=1;i<=n;i++)
40     {
41         for(int j=h2/2;j>=ny[i];j--)
42         {
43             f[j]|=f[j-ny[i]];
44         }
45     }
46     mx=0;
47     for(int i=1;i<=h2/2;i++) if(f[i]) mx=i;
48     ans+=(h2-2*mx)*(h2-2*mx);
49     printf("%.2lf
",ans*1.0/2);
50     return 0;
51 }
View Code

2017-04-06 16:45:10

原文地址:https://www.cnblogs.com/Konjakmoyu/p/6674225.html