【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: 153Description
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\n",ans*1.0/2); 50 return 0; 51 }
2017-04-06 16:45:10