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 }
时间: 2024-08-06 11:34:26

BZOJ 4089:[Sdoi2015]graft(SDOI 2015 Round 2 Day 2)的相关文章

BZOJ 4085:[Sdoi2015]bigyration(SDOI 2015 round 2 Day 1)

别人家的神选系列.Day2根本不能做QAQ 题目描述:给定两个字符串集合,一个长度为n,另一个为m,求有多少个数字对i,j,满足xi+yj能由一个(n+m)/2的字符串旋转拼接而成 我们枚举长度较长的集合,那么我们的那个(n+m)/2的字符串就能确定了,接下来我们就可以对y的字符串hash掉然后枚举断点就能o(1)判断啦 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<a

SDOI 2015

集训又开始了…… 省选,省选.这是每个OIer在竞赛之路上面临的巨大挑战,也是我这种压线国一省选无望的高一狗的悲痛.下周五就要Round1了,现在还是大字不识一个的文盲水平,满篇的高大上算法不会,低级搜索DP写的拙到家,终极算法——乱搞也没搞出什么鬼.昨晚的一次模拟赛,搜了俩结果全爆零……所有的现实摆在眼前,每省十几名的省队名额真是遥不可及,但是,毕竟比赛还没开始,即使真的离我很远,那又有什么呢? 还没上战场,怎能就这样把自己否定了呢?即使希望再渺茫,也不能开始就认定自己是去捐钱的.虽然身边的各

【搜索】BZOJ 3990: 【Sdoi 2015】排序

3990: [SDOI2015]排序 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 336  Solved: 164[Submit][Status][Discuss] Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到右划分为2^{N-i+1}段,每段恰好包括2^{i-1}个数,然后整体交换

BZOJ 4085:[Sdoi2015]quality(round 2 音质检测)(数据结构)

居然在考场上把这道题打出来了觉得自己也是有点吊啊(虽然后面就没时间做其他题了囧而且还被卡常数了...) 题解自己写了一份TEX的就直接放上来吧.... 好啦,在谈点什么别的 什么?你在bz上TLE了?注意一下你的矩阵乘法,这个程序的大部分时间几乎都是跑矩阵乘法的,我是从900000次到600000次在到300000次最后预处理那些2的次幂才过的.把OJ卡了好久真是对不起啊QAQ CODE: 1 #include<cstdio> 2 #include<iostream> 3 #inc

BZOJ 3990 [SDOI 2015] 排序 解题报告

这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 $O(2^n)$ 枚举每个操作进不进行,再去判断,如果可行就 $ans$ += $|S|!$. 然而怎么判断呢? 我们按照操作种类从小到大操作. 假设我们现在在决策第 $i$ 种操作并且保证之前之后不需要进行种类编号 $< i$ 的操作. 那么我们只考虑那些位置在 $2^i+1$ 的位置的那些数.

BZOJ 3993 [SDOI 2015] 星际战争 解题报告

首先我们可以二分答案. 假设当前二分出来的答案是 $Ans$ ,那么我们考虑用网络流检验: 设武器为 $X$,第 $i$ 个武器的攻击力为 $B_i$: 设机器人为 $Y$,第 $i$ 个机器人的装甲为 $A_i$: 设 $Map[i][j]$ 表示第 $i$ 个机器人是否能攻击第 $j$ 号机器人. 设源为 $S$,汇为 $T$,现在考虑连边: $S\rightarrow X_i$,容量为 $Ans * B_i$: $Y_i\rightarrow T$,容量为 $A_i$: $\forall

BZOJ 3994: [SDOI2015]约数个数和

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 898  Solved: 619[Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7

BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂

3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1155  Solved: 532[Submit][Status][Discuss] Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中

BZOJ 3994 [SDOI2015]约数个数和 (神定理+莫比乌斯反演)

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec  Memory Limit:128 MB Submit: 239  Solved: 176 [Submit][Status][Discuss] Description 设d(x)为x的约数个数,给定N.M,求   Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Output T行,每行一个整数,表示你所求的答案. Sample Input 2 7