题意
n个点,有点权,正数或负数,可以连边,边的代价为两端点权的积,但要满足最终的图每个点度数大于0,且一个正数点不能连超过1个负数点
数据范围
3e4,可以到2e5
样例
input
4
-1 2 -3 4
output
-15
(-3向其他连边)
显然不会成环,有环必有正数,因此答案一定是生成森林
如果仅有正数或仅有负数,那么肯定是最大连最小,次大连次小……
既有正数又有负数的话
将正数负数分别从大到小连边,
连边和下图类似:
这样就可以用FFT优化啦
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 65536
#define ll long long
#define db double
using namespace std;
int n,rev[N],a[N],b[N];
ll sm1[N],sm2[N],A[N],B[N],C[N],D[N],E[N],F[N];
struct complex{
db a,b;complex(db _a=0,db _b=0){a=_a,b=_b;}
}w[N];
complex operator+(complex a,complex b){return complex(a.a+b.a,a.b+b.b);}
complex operator-(complex a,complex b){return complex(a.a-b.a,a.b-b.b);}
complex operator*(complex a,complex b){return complex(a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a);}
void fft(complex *a){
for(int i=1;i<N;++i)if(rev[i]<i)swap(a[i],a[rev[i]]);complex *s,*t,T,*W;
for(int h=1,m=2,i,j,g=N>>1;h<N;h=m,m<<=1,g>>=1)for(i=0,s=a;i<N;i+=m,s=t)
for(W=w,t=s+h,j=0;j<h;++j)T=*t**W,*t=*s-T,*s=*s+T,++s,++t,W+=g;
}
void ifft(complex *a){
for(int i=1;i<N>>1;++i)swap(a[i],a[N-i]);fft(a);
for(int i=0;i<N;++i)a[i]=complex(a[i].a/N,a[i].b/N);
}
void mult(ll *a,ll *b,ll *c){
static complex A[N],B[N],C[N],D[N];
for(int i=0;i<N;++i){
int sig=a[i]<0?-1:1;a[i]=sig*a[i];
A[i]=complex((a[i]>>12)*sig,0);B[i]=complex((a[i]&4095)*sig,0);
sig=b[i]<0?-1:1;b[i]=sig*b[i];
C[i]=complex((b[i]>>12)*sig,0);D[i]=complex((b[i]&4095)*sig,0);
}fft(A);fft(B);fft(C);fft(D);
for(int i=0;i<N;++i){
complex t=B[i];
B[i]=(A[i]*D[i])+(B[i]*C[i]);
A[i]=A[i]*C[i];C[i]=t*D[i];
}ifft(A);ifft(B);ifft(C);
for(int i=0;i<N;++i){
ll ca=round(A[i].a),cb=round(B[i].a),cc=round(C[i].a);
c[i]=ca*(1<<24)+cb*4096+cc;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",a+i);
int n1=0,n2=0;
for(int i=1;i<=n;++i)if(a[i]<0)b[++n2]=a[i];else a[++n1]=a[i];
sort(a+1,a+n1+1);sort(b+1,b+n2+1);
if(!n2){
for(int i=1;i<=n1;++i)b[n1+1-i]=-a[i];
n2=n1;n1=0;
}
for(int i=0;i<N;++i){
db ang=2.0*M_PI/N*i;
rev[i]=(rev[i>>1]>>1)+(i&1)*(N>>1);
w[i]=complex(cos(ang),sin(ang));
}
for(int i=1;i<=n2;++i)D[i]=E[i]=B[i]=b[i];mult(D,E,F);
for(int i=1;i<=n1;++i)A[i]=a[i];mult(A,B,C);
for(int i=n1;i;--i)sm1[i]=sm1[i+1]+1ll*a[i]*b[1];
for(int i=1;i<=n2;++i)sm2[i]=sm2[i-1]+1ll*b[i]*b[n2];
if(n2==1){printf("%lld\n",sm1[1]);return 0;}
ll mn=sm2[n2-1];int p=2;
for(int i=4;i<=n2;i+=2){
ll v=sm2[n2-i]+F[n2+n2-i+1]/2;
if(v<mn)mn=v,p=i;
}
if(n1==0){printf("%lld",mn);return 0;}
ll ans=8000000000000000000;
for(int i=max(0,n2-n1);i<=n2;++i){
ll tmp;
if(i==1)tmp=1ll*b[n2]*b[n2-1];else
if(i<p){
if(i&1)tmp=F[n2+n2-i+2]/2+1ll*b[n2-i+1]*b[n2];else tmp=F[n2+n2-i+1]/2;
}else tmp=mn-sm2[n2-i];
ll v=tmp+sm1[n2-i+1]+C[n2-i+1];
if(v<ans)ans=v;
}printf("%lld",ans);
}