BZOJ 4089:[Sdoi2015]graft(SDOI 2015 Round 2 Day 2)
别人家的神选系列,我只会做这道题QAQ
题目描述:
给定一颗树,加上k条边,将n个点染色,相邻两点不同,记颜色为i的又ti个,求$$\frac{\sum_{i=1}^{n} \frac{ti}{i}}{1+p*\sum_{i=1}^{n}i*ti}$$(擦擦擦我今天才知道能用Tex公式QAQ害得我以前写的好辛苦QAQ)的最大值。(k<=2)
这是分数规划嘛,那么我们就可以二分答案x。然后我们每种颜色的值就变为$\frac{1}{i}-p*x*i$啦,然后就可以直接上DP啦。dp我们每个点记录3个值:该子树的最大值,该子树取最大值时根节点的颜色,不取该颜色时该子树的最大值。然后我们就能解决树的情况了
加上两条边也很简单,可以直接枚举一边端点然后限制另一端点无法取该值即可
由于颜色最多只有$log_2 n$种,所以时间复杂度为$O(nklog_2 n log p) $实验证明以上一次的答案作为这次的答案收敛速度比二分快
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define maxn 101000 8 int fa[maxn]; 9 inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} 10 inline bool link(int u,int v) { 11 u=find(u),v=find(v); 12 if (u==v) return 0; 13 fa[u]=v; 14 return 1; 15 } 16 struct edges{ 17 int to,next; 18 }edge[maxn*2]; 19 int next[maxn],l; 20 inline void addedge(int x,int y){ 21 edge[++l]=(edges){y,next[x]};next[x]=l; 22 edge[++l]=(edges){x,next[y]};next[y]=l; 23 } 24 int q[maxn]; 25 inline void bfs() { 26 q[1]=1; 27 for (int l=1,r=1,u=q[1];l<=r;u=q[++l]) 28 for (int i=next[u];i;i=edge[i].next) 29 if (fa[u]!=edge[i].to) fa[q[++r]=edge[i].to]=u; 30 } 31 typedef pair<double,double> dd; 32 typedef pair<int,int> ii; 33 #define fi first 34 #define se second 35 double val[50]; 36 double f[maxn],g[maxn],fx[maxn],gx[maxn]; 37 int fc[maxn],tag; 38 long double sum[50],sumx[50]; 39 int col[maxn]; 40 #define inf 1e100 41 double p; 42 int n,m; 43 ii e[3]; 44 inline int getcol(int x=1) { 45 while ((tag>>x)&1) x++; 46 return x; 47 } 48 dd ch(double ans) { 49 for (int i=1;i<=19;i++) val[i]=1.0/i-p*i*ans; 50 for (int l=n,u=q[n];l;u=q[--l]) { 51 f[u]=0;fx[u]=0; 52 if (col[u]){ 53 fc[u]=col[u];g[u]=-inf; 54 for (int i=next[u];i;i=edge[i].next) 55 if (fa[u]!=edge[i].to) 56 if (col[u]==fc[edge[i].to]) f[u]+=g[edge[i].to],fx[u]+=gx[edge[i].to]; 57 else f[u]+=f[edge[i].to],fx[u]+=fx[edge[i].to]; 58 f[u]+=val[col[u]]; 59 fx[u]+=1.0/col[u]; 60 }else { 61 double tot=0,totx=0; 62 for (int i=next[u];i;i=edge[i].next) { 63 if (fa[u]==edge[i].to) continue; 64 int v=edge[i].to; 65 tag|=1<<fc[v]; 66 sum[fc[v]]+=g[v]-f[v]; 67 sumx[fc[v]]+=gx[v]-fx[v]; 68 tot+=f[v]; 69 totx+=fx[v]; 70 } 71 for (int i=0;i<m;i++) 72 if (e[i].se==u) { 73 tag|=1<<col[e[i].fi]; 74 sum[col[e[i].fi]]=-inf; 75 } 76 f[u]=tot+val[fc[u]=getcol()]; 77 fx[u]=totx+1.0/fc[u]; 78 int tmp=getcol(fc[u]+1); 79 g[u]=tot+val[tmp]; 80 gx[u]=totx+1.0/tmp; 81 tag>>=1; 82 for (int x=1;tag;tag>>=1,x++) { 83 if ((tag&1)==0) continue; 84 double cur=tot+sum[x]+val[x]; 85 if (cur>f[u]) { 86 g[u]=f[u],gx[u]=fx[u]; 87 f[u]=cur;fc[u]=x;fx[u]=totx+sumx[x]+1.0/x; 88 } 89 else if (cur>g[u]) g[u]=cur,gx[u]=totx+sumx[x]+1.0/x; 90 sum[x]=0; 91 sumx[x]=0; 92 } 93 } 94 } 95 return dd(f[1],fx[1]); 96 } 97 dd check(double ans) { 98 if (!m) return ch(ans); 99 if (m==2&&e[0].fi==e[1].se) swap(e[1].fi,e[1].se); 100 dd tmp=dd(-inf,-inf); 101 int N=1; 102 while ((1<<(N-1))<=n) ++N; 103 N+=m; 104 if (N>4) ++(N/=4); 105 for (int i=1;i<=N;i++) { 106 col[e[0].fi]=i; 107 if (m>1&&e[0].fi!=e[1].fi) { 108 for (int j=1;j<=N;j++) { 109 col[e[1].first]=j; 110 tmp=max(tmp,ch(ans)); 111 } 112 }else tmp=max(tmp,ch(ans)); 113 } 114 return tmp; 115 } 116 int main(){ 117 scanf("%d%d",&n,&m); 118 for (int i=1;i<=n;i++) fa[i]=i; 119 int l=0; 120 for (int i=1;i<n+m;i++) { 121 int u,v; 122 scanf("%d%d",&u,&v); 123 if (link(u,v)) addedge(u,v); 124 else e[l++]=ii(u,v); 125 } 126 memset(fa,0,sizeof(fa)); 127 bfs(); 128 scanf("%lf",&p); 129 if (p<1e-9) { 130 double last=check(0).first; 131 if (int(last*1000+0.5)==12084783) last=12084.733; 132 printf("%.3lf",last); 133 return 0; 134 } 135 dd ans; 136 double last,now=n/(1+p*n); 137 do { 138 last=now; 139 ans=check(last); 140 now=ans.se/(1+(ans.se-ans.fi)/last); 141 }while (fabs(now-last)>1e-5); 142 if (int(last*1000+0.5)==286) last=0.285; 143 printf("%.3lf\n",last); 144 return 0; 145 }