对于 100% 的数据,保证0<n<=200,0<x,y<=200。
首先 根据公式 n个数和m个数两两相乘的结果为n个数的和与m个数的和的积
而且x和y互不影响
于是套公式-两两相乘/2-交集 结果为 f(n)= (x1+..+xn)^2+x1^2+..xn^2 )/2
易证 f(n)=(x1+...+xn-1)* xn + f(n-1)
所以 xn 要么最大,要么最小 才能使 f(n)有最大/最小值
因为不知道 (x1+..x(n-1)的正负 所以只能靠猜( 既考虑最大,也考虑最小)
回到原公式 显然 要是 f(n)有最小值 就要另 (x1+..+xn)有最小值
于是就是分组背包各种做……
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<cmath> #include<functional> #include<algorithm> using namespace std; #define MAXN (200+10) #define MAXV ((40000+100)*2) #define MAXX (200+10) #define f(i,j) f[ (i) ][ (j)+20000 ] int n; long long ans=0; bool f[MAXN][MAXV]; int x[MAXN]; int y[MAXN]; int sqr(int x) { return x*x; } int main() { freopen("bicycle.in","r",stdin); freopen("bicycle.out","w",stdout); cin>>n; for (int i=1;i<=n;i++) { cin>>x[i]>>y[i]; ans-=(long long)(sqr(x[i]))+sqr(y[i]); } memset(f,0,sizeof(f)); f(0,0)=1; for (int i=1;i<=n;i++) for (int j=-i*200;j<=i*200;j++) f(i,j)=f(i-1,j-x[i])||f(i-1,j+x[i]); int j=0; while (!f(n,j)&&!f(n,-j)) j++; ans+=(long long)j*j; // cout<<j<<endl; /* int j=0; for (int i=0;i<=n;i++) { for (int j=-10;j<=10;j++) cout<<f(i,j); cout<<endl; } */ memset(f,0,sizeof(f)); f(0,0)=1; for (int i=1;i<=n;i++) for (int j=-i*200;j<=i*200;j++) f(i,j)=f(i-1,j-y[i])||f(i-1,j+y[i]); j=0; while (!f(n,j)&&!f(n,-j)) j++; ans+=(long long)j*j; cout.setf(ios::fixed); cout.precision(2); cout<<double(ans)/2<<endl; // while (1); return 0; }