NOIP2014 提高组复赛
1002. 联合权值
- 树形dp
想用树形dp进行收集的时候,把儿子们的信息给重新收集一遍了,还用了邻接表(甚至本来想用vector)。实际上在收集的时候只要维护权值总和以及最大权值就好了,而不需要再把所有儿子重新提出来再处理。因为这个地方没有优化结果TLE了三组……qvq
但是简直比Tyvj的模拟题还水……好歹人家有五个点……
按照树形dp的思想,我们统计经过当前子树的根的,这棵子树内符合条件的三元点对数目。那么对于这个根,它有两种情况:
- 根是三元点对中的中间结点,此时两端节点是它的儿子中的任意一对。
- 根是三元点对中的两端节点,此时另一端节点是它的孙子。
这样显然是不会重复的,因为我们只考虑当前子树的情况(即不考虑父亲和祖父节点等的情况),并且一定收集包含根结点的三元点对。那么我们只需要统计孙子节点和儿子节点的权值和与最大权值(孙子节点的数据在以儿子节点为根的时候已经收集到了),于是时间复杂度为 O(n) 。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define M 200005
#define P 10007
#define clear(x,val) memset(x,val,sizeof(x))
using namespace std;
template <class temp>
inline void Rd(temp &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>47);
}
inline void Mod(int &a,int b){a+=b;if(a>=P)a-=P;}
//-----------------------
int n,w[M];
int head[M],htop=0;
struct node{
int v,nxt;}Nodes[M<<1];
int mxson[M],sumson[M];
void add_edge(int u,int v){
Nodes[++htop]=(node){v,head[u]};head[u]=htop;
Nodes[++htop]=(node){u,head[v]};head[v]=htop;
}
int val,mx=0,ans=0;
void dfs(int u,int pre){
for(int j=head[u];~j;j=Nodes[j].nxt){
int v=Nodes[j].v;
if(v==pre)continue;
dfs(v,u);
mx=max(mxson[u]*w[v],mx);
if(mxson[u]<w[v])mxson[u]=w[v];
Mod(ans,sumson[u]*w[v]%P);
Mod(sumson[u],w[v]);
mx=max(mxson[v]*w[u],mx);
Mod(ans,sumson[v]*w[u]%P);
}
}
int main(){
clear(head,-1);
Rd(n);
for(int i=1,u,v;i<n;i++)
Rd(u),Rd(v),add_edge(u,v);
for(int i=1;i<=n;i++)Rd(w[i]);
dfs(1,0);
Mod(ans,ans);
printf("%d %d\n",mx,ans);
}
如果不从正常的树形dp考虑,那么我们就枚举每个点作为中心节点的情况,此时它周围一圈的相邻节点中均可以构成两端点对。于是每次统计一下,时间复杂度为 O(n) 。
1003. Flappy Bird
- 背包dp
玩Codevs的玩了这么久还A不掉也是可以。又是受了上次NOIP2013_day2_task3华容道那题的影响……居然肛在选择dfs还是bfs好久……然而我一开始还是敲了dfs qvq,真的害怕如果标程又是dfs,然后我居然写了bfs,那时候我会哭的一脸懵逼的。
后来硬是改成了Dijkstra,想想复杂度有点高于是准备改成队列……虽然没改成功,但是我最后意识到——这题是不是可以用背包做。 qvq 但是硬是水了75分,比暴力背包高(难道完全背包的优化不暴力么……)。
bfs还是简单的,只不过由于每次转移的边权在 [0,m] 中,不是恒定的1,所以只能用堆弹。时间复杂度为 O(n×m2logn)