【WC2015模拟2.6】Tree

本文介绍了一个涉及图论和动态规划的复杂问题:在一个无根树中通过调整点权并选择不相交路径来最大化收益。文章详细阐述了解决方案的过程,包括如何使用二分查找优化解的空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出一个n个节点的无根树,每个点有点权。
你要选择一些不相交的路径,如果选择了k条路径,点权和为sum,那么它的价值为sumk+1
你必须在选择前选择一个数C(0<=c<=T),将所有点权加上C再对limit取模。
求你能收获的最大价值。
N<=10^5,T< limit<=10^6

Solution

昨天才讲完这种题的思路,今天就出了一道题2333
首先可以二分答案啊,然后对于一个mid,判断它是否合法。
就是看sumk+1>=mid
sum>=mid(k+1)
sumkmid>=mid
那么我们只需要将每一条选择的路径的权值减去mid就好了。
这个东西显然可以Dp。
设F[i][0\1]表示i这个点为根的子树中的权值最大值,和一定能往上继续扩展的权值最大值。
这个东西可以通过前缀和做到O(N)
然后考虑枚举这个C
发现如果我们枚举的这个C,使得点权的最大值不是limit-1,那么C+1显然会比C更优。
于是我们枚举每个点权,将其加到limit-1作为一个C值。
这样做的复杂度就降到O(N^2E)了,其中E是二分的复杂度。
不过这样子做的复杂度还是太高,毕竟二分要写实数。
然后题解神奇的随机化了一发~
随机枚举这N个取值,并且在二分之前判断这个取值是否合法
然后复杂度就降下来了?!
不会证明,我是卡常卡过的(雾

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define max(a,b) (a>b)?a:b
using namespace std;
typedef double db;
const int N=5*1e3+5,M=1e6+5,inf=0x7fffffff;
int n,l,x,y,tot,limit,T,mx,v[N],V[N],w[N],d[N],q[N];
int last[N],next[N*2],t[N*2];
db ans,f[N][2],sum[N],pre[N],eps=1e-7;
bool h[M];
int get() {
    char ch;while (!isdigit(ch=getchar()));
    int o=ch-48;while (isdigit(ch=getchar())) o=o*10+ch-48;
    return o;
}
void add(int x,int y) {
    t[++l]=y;next[l]=last[x];last[x]=l;
}
void dfs(int x,int y,db z) {
    rep(i,x) if (t[i]!=y) dfs(t[i],x,z);
    q[0]=sum[0]=0;pre[0]=-inf;
    rep(i,x) if (t[i]!=y) q[++q[0]]=t[i];
    fo(i,1,q[0]) sum[i]=sum[i-1]+f[q[i]][1];
    fo(i,1,q[0]) pre[i]=max(pre[i-1]+f[q[i]][1],sum[i-1]+f[q[i]][0]);
    f[x][1]=sum[q[0]];f[x][0]=sum[q[0]]+v[x]-z;
    fo(i,1,q[0]) f[x][0]=max(f[x][0],f[q[i]][0]+sum[q[0]]-f[q[i]][1]+v[x]);
    fo(i,1,q[0]) f[x][1]=max(f[x][1],f[q[i]][0]+pre[i-1]+v[x]+z+sum[q[0]]-sum[i]);
    f[x][1]=max(f[x][1],f[x][0]);
}
void solve(int x) {
    db l=ans,r=5*1e8;
    fo(i,1,n) v[i]=(V[i]+x)%limit;
    dfs(1,0,ans+eps);
    if (max(f[1][0],f[1][1])<ans+eps) return;
    while (r-l>eps) {
        db mid=(l+r)/2.0;
        dfs(1,0,mid);
        if (max(f[1][0],f[1][1])>=mid) l=mid;
        else r=mid; 
    }
    ans=l;
}
int main() {
    n=get();limit=get();
    fo(i,1,n) V[i]=get(),V[i]%=limit,mx=max(mx,V[i]);
    fo(i,1,n-1) x=get(),y=get(),add(x,y),add(y,x);
    T=get();
    fo(i,1,n) if (limit-V[i]-1<=T&&!h[limit-V[i]-1]) solve(limit-V[i]-1),h[limit-V[i]-1]=1;
    if (mx+T<limit-1) solve(T);
    printf("%.6lf\n",ans);
}
wc2015】未来程序是指在未来可能出现的新型计算机程序,具备更加先进、高效、智能的功能和特。随着科技的不断进步,程序开发也将朝着更加智能化、自动化的方向发展。 首先,未来程序可能具备更强大的人工智能能力。目前的人工智能已经可以实现语音识别、图像识别等基本功能,未来程序有望拥有更高级的人工智能技术,能够更加深入地理解和分析人类语言、情感和意图,甚至能够进行自主的学习和创新。 其次,未来程序可能会具有更高效的算法和计算能力。随着计算机硬件技术的不断改进,未来程序可能会利用更先进的算法和更强大的计算资源,从而提高程序的执行速度和效率,使得软件能够更好地适应各种应用场景。 另外,未来程序可能会更加注重安全性和隐私保护。随着网络的普及和信息的大规模交换,数据安全和隐私问题越来越受到关注。未来程序将会加强对数据的保护,采用更安全的数据传输和存储技术,确保用户的信息和隐私不受侵犯。 最后,未来程序可能会更加注重可持续发展和环境友好。随着全球环境问题的日益严重,未来程序可能会采用更加节能、环保的设计和开发方式,减少对能源和资源的消耗,从而更好地满足可持续发展的需求。 总之,未来程序将是更加智能、高效、安全、环保的计算机程序,能够更好地满足人们的各种需求和期待。随着科技的不断进步,未来程序的发展潜力将是无限的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值