【CF839E】Mother of Dragons 折半状压
【CF839E】Mother of Dragons
题意:给你一张n个点,m条边的无向图。你有k点能量,你可以把能量分配到任意一些点上,每个点分到的能量可以是一个非负实数。定义总能量为:对于所有边<a,b>,a的能量*b的能量 的和。让你最大化总能量。
$n\le 40,k\le 1000$
题解:容易发现,最后的分配方案一定是给一个大小为cnt的完全子图中的每个点都分配$k\over cnt$点能量。
那么本题就变成了一般图最大团问题,可以用随机化搞定,这里给出一种meet in the middle算法。
对于前一半的点,用状压预处理出f[S]表示S中的最大团是什么。对于后一半的点,我们可以枚举其中的所有最大团,然后把与这些点都相邻的前一半的点拿出来,用前一半点的f值+后一半点的团大小更新答案即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; int n,m,n1,n2; double k; const int N=(1<<20)+4; ll v[50]; int f1[N],Log[N],g[N],f2[N],cnt[N]; int main() { scanf("%d%lf",&n,&k); int i,j,a; for(i=0;i<n;i++) for(j=0;j<n;j++) { scanf("%d",&a); if(a) v[i]|=1ll<<j,v[j]|=1ll<<i; } n1=n/2,n2=n-n/2; for(i=0;i<n2;i++) Log[1<<i]=i; for(i=1;i<(1<<n1);i++) { a=Log[i&-i]; f1[i]=max(f1[i^(1<<a)],f1[i&v[a]]+1); } m=f1[(1<<n1)-1]; g[0]=1,f2[0]=(1<<n1)-1; for(i=1;i<(1<<n2);i++) { a=Log[i&-i]; f2[i]=f2[i^(1<<a)]&v[a+n1],cnt[i]=cnt[i^(1<<a)]+1; if(g[i^(1<<a)]&&(((v[a+n1]>>n1)&i)==(i^(1<<a)))) g[i]=1,m=max(m,f1[f2[i]]+cnt[i]); } printf("%.10f",k*k*(m-1.0)/m/2.0); return 0; }