话说题目好像有点难,好吧就是我的锅。
下面主要是一点提示和我自己的ac代码。
A:这是一道树形dp(勉强这么说吧)。
贪心的思路如下,如果一颗子树经过某些操作可以使其变成全0,那么无论以怎样的顺序执行这些操作,都可以使其达到全0状态。
记add[i],cut[i]为对于以i为根的子树达成全零需要加,减的操作数
那么,对于某个节点u,先递推求解子节点的add和cut,u节点的add值就是子节点add值得最大值,cut值同样
再用u本身的值+add-cut,这就是使u的子节点的子树全0后u的状态,如果这个值大于0,cut值再加上它,否则add值加上他的绝对值
具体见代码
(题目评价:树形dp+贪心思想)
<span style="font-size:14px;">#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#include <assert.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
struct edge {
int v,nex;
}e[maxn*2];
int ee,p[maxn],fa[maxn];
void addedge (int u,int v) {
e[ee].v=v;e[ee].nex=p[u];p[u]=ee++;
e[ee].v=u;e[ee].nex=p[v];p[v]=ee++;
}
ll add[maxn],cut[maxn],val[maxn];
void dfs(int u) {
int v;add[u]=0;cut[u]=0;
for(v=p[u];~v;v=e[v].nex) {
if(e[v].v==fa[u]) continue;
fa[e[v].v]=u;dfs(e[v].v);
add[u]=max(add[u],add[e[v].v]);
cut[u]=max(cut[u],cut[e[v].v]);
}
val[u]+=add[u]-cut[u];
if(val[u]>=0) cut[u]+=val[u];
else add[u]+=val[u]*-1;
}
int main()
{
// freopen("aa.txt","r",stdin);
int i,n,x,y;
scanf("%d",&n);
ee=0;memset(p,-1,sizeof(p));
for(i=1;i<n;i++) {
scanf("%d%d",&x,&y);
addedge(x,y);
}
for(i=1;i<=n;i++) scanf("%I64d",&val[i]);
dfs(1);
cout<<add[1]+cut[1]<<endl;
}</span>
B:百度之星的一题
题目要求严格递增,如果只要求非减,只要直接dp出最长非减子序列。。。
那么这题怎么写?
考虑对于每一个值,让他减去自身的序号,这样得到一个新的序列。
对于新的序列,求出他的最长非减子序列,那么只要保留这个子序列,改变其余值即可满足题意。
代码是很久之前写的,写了一个很挫的二分,其实用upper_bound即可
<span style="font-size:14px;">#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
using namespace std;
int dp[(int)1e5+5],a[(int)1e5+5],leng; //dp[i]位长度为i的非减子序列最小的末尾值
int find(int len,int n)
{
int left=0,right=len,mid=(left+right)/2;
while(left<=right)
{
if(n>dp[mid]) left=mid+1;
else if(n<dp[mid]) { right=mid; if(right==left) break;}
else { while(n==dp[mid]) mid++; return mid; }
mid=(left+right)/2;
}
return left;
}
int main()
{
int T,cas;
scanf("%d",&T);
dp[0]=-9999999;
for(cas=1;cas<=T;cas++) {
leng=0;
int n,i,j;
scanf("%d",&n);
for(i=1;i<=n;i++) {
scanf("%d",&a[i]);
a[i]=a[i]-i;
dp[i]=9999999;
}
for(i=1;i<=n;i++) {
j=find(leng+1,a[i]); //j=upper_bound(dp,dp+leng+1,a[i])-dp;
dp[j]=min(dp[j],a[i]);
leng=max(leng,j); // leng为已经求得最长的子序列长度
}
leng=n-leng;
cout<<"Case #"<<cas<<":"<<endl<<leng<<endl;
}
}</span>