联合权值
来源:互联网 发布:程序员出差是去干什么 编辑:程序博客网 时间:2024/05/21 09:15
好。。。
一开始做的暴力只有60分
code
#include<cstdio>using namespace std;int head[200001];int len=0;struct data{ int next,to;}e[400001];void connect(int x,int y){ e[++len].next=head[x]; e[len].to=y; head[x]=len; e[++len].next=head[y]; e[len].to=x; head[y]=len;}long long ans=0,anss=0;long long va[200001];int p[200001];int max(int x,int y){ if (x>y) return x; else return y;}int ls[200001];int dfs(int x){ p[x]=1; int tmp=0; int l=0; for (int k=head[x];k;k=e[k].next) { int o=e[k].to; if (p[o]==0) {for (int i=1;i<=l;++i) { ans=(ans+ls[i]*va[o]*2)%10007; anss=max(anss,ls[i]*va[o]); } ls[++l]=va[o]; } } int pd=0; for (int i=head[x];i;i=e[i].next) { int v=e[i].to; if (p[v]) continue; for (int j=head[v];j;j=e[j].next) { int u=e[j].to; if (x!=u) { ans=(ans+va[x]*va[u])%10007; ans=(ans+va[x]*va[u])%10007; anss=max(anss,va[x]*va[u]); } } dfs(v); }}void ycl(int x){ p[x]=1; for (int i=head[x];i;i=e[i].next) { int v=e[i].to; if (p[v]) e[i].next=e[e[i].next].next; else ycl(v); }}int main(){ int n; scanf("%d",&n); for (int i=1;i<=n-1;++i) { int x,y; scanf("%d%d",&x,&y); connect(x,y); } for (int i=1;i<=n;++i) scanf("%d",&va[i]); ycl(1); dfs(1); printf("%lld %lld",anss,ans);}
还创造性的进行了砍边,结果还是tttt
想到了用把子节点和加起来的方式优化,但貌似求不了最大值(IQ低)
两个点之间要想产生联合权值,中间必须隔着一个点。我们可以以隔着的这个点为突破口。
问题一:最大值是多少?
我们枚举中间的那个点,在和这个点有连边的所有点中,找出权值最大的两个点即可。
问题二:计算联合权值的和?
还是枚举中间的那个点。比较笨的方法是两层枚举
假设和当前枚举的中间点有边相连的有a,b,c,d,e,……这些点,我们计算a*b+a*c+a*d+…+b*c+b*d+b*e+…+c*d+c*e+…
这样复杂度最坏可能到n^2级别。
怎样能够快速求出权值和?
令sum=a+b+c+…,我们只需要计算[a*(sum-a)+b*(sum-b)+…]/2即可。
code
#include<cstdio>using namespace std;int head[200001];int len=0;struct data{ int next,to;}e[400001];void connect(int x,int y){ e[++len].next=head[x]; e[len].to=y; head[x]=len; e[++len].next=head[y]; e[len].to=x; head[y]=len;}long long ans=0,anss=0;long long va[200001];int max(int x,int y){ if (x>y) return x; else return y;}int ls[200001];int p[200001];int dfs(int x){ p[x]=1; int zd1=0,zd2=0; int tmp=0; for (int i=head[x];i;i=e[i].next) { int value=va[e[i].to]; tmp+=value; if (value>zd1) zd1=value; else if (value>zd2) zd2=value; } anss=max(anss,zd1*zd2); for (int i=head[x];i;i=e[i].next) { int v=e[i].to; ans=(ans+tmp*va[v]-va[v]*va[v])%10007; if (p[v]==0) dfs(v); }}int main(){ int n; scanf("%d",&n); for (int i=1;i<=n-1;++i) { int x,y; scanf("%d%d",&x,&y); connect(x,y); } for (int i=1;i<=n;++i) scanf("%d",&va[i]); dfs(1); printf("%lld %lld",anss,ans);}
其实一开始的暴力如果想到怎么求最大值就过了QAQ
#include<cstdio>using namespace std;int head[200001];int len=0;struct data{ int next,to,last;}e[400001];void connect(int x,int y){ e[++len].next=head[x]; e[len].to=y; head[x]=len; e[++len].next=head[y]; e[len].to=x; head[y]=len;}long long ans=0,anss=0;long long va[200001];int p[200001];int max(int x,int y){ if (x>y) return x; else return y;}int ls[200001];int dfs(int x){ int tmp=0; int l=0; int zd1=0,zd2=0; for (int k=head[x];k;k=e[k].next) { int o=e[k].to; tmp+=va[o]; if (va[o]>zd1) zd1=va[o]; else if (va[o]>zd2) zd2=va[o]; } anss=max(anss,zd2*zd1); int pd=0; for (int i=head[x];i;i=e[i].next) { int v=e[i].to; for (int j=head[v];j;j=e[j].next) { int u=e[j].to; if (x!=u) { ans=(ans+va[x]*va[u])%10007; ans=(ans+va[x]*va[u])%10007; anss=max(anss,va[x]*va[u]); } } ans=(ans+va[v]*tmp-va[v]*va[v])%10007; dfs(v); }}void ycl(int x){ p[x]=1; while (p[e[head[x]].to]) head[x]=e[head[x]].next; int d=head[x]; for (int i=head[x];i;i=e[i].next) { int v=e[i].to; if (p[v]) { e[d].next=e[i].next; d=e[e[i].next].next; } else { ycl(v); d=i; } }}int main(){ int n; scanf("%d",&n); for (int i=1;i<=n-1;++i) { int x,y; scanf("%d%d",&x,&y); connect(x,y); } for (int i=1;i<=n;++i) scanf("%d",&va[i]); ycl(1); dfs(1); printf("%lld %lld",anss,ans);}
1 1
- NOIP2014 联合权值
- NOIP2014联合权值
- NOIP2014联合权值
- Codevs 联合权值
- 联合权值
- 【noip2014】联合权值
- Vijos1096 联合权值
- NOIP2014 联合权值
- 【NOIP2014】 联合权值
- 联合权值
- noip2014联合权值
- NOIP2014 联合权值
- 联合权值
- 【NOIP2014】联合权值
- 【NOIP2014 联合权值】
- [NOIP2014]联合权值
- 3728 联合权值
- luoguP1351 联合权值
- Hello world !
- Python 两个图形小程序
- 关于点击事件的触发器具体使用方法
- noip2012同余方程 (拓展欧几里得)
- 吐槽一下CSDN的OpenAPI
- 联合权值
- easyui 1.5+spring mvc +mybatis实例代码
- C++学习笔记(三) linux的基本使用和linux C —参考慕课网
- make和makefile以及程序的编译和链接过程
- 勾股定理一日一证连载150
- 欧拉函数
- Configuring boot servlet context and filters
- Java程序设计——窗口小程序
- 当JavaScript遇上UINT64