今年原地起爆,没进复赛,看别的dalao码代码各种AK虐场心痒痒,来写个题解
Day2还在肝,就先写Day1吧……
NOIP2013年原题,用个滚动数组就能水过去了……(不用应该也行吧)
做法大概是从头开始扫,记录每个位置的深度,然后读入一个深度,如果后面的更深就需要多填 后面的深度 − - −前面的深度 次
#include
using namespace std;
int n,a,b;
long long ans;
int main()
{
scanf("%d%d",&n,&b);
ans=b;
for(int i=1;i<n;i++)
{
scanf("%d",&a);
if(a>b) ans+=a-b;
b=a;
}
printf("%lld",ans);
return 0;
}
明显的DP背包题,想不到的话使用DFS+DP可以获得65(洛咕数据)的好成绩
把面值排个序,从头向后扫,如果 f [ a [ i ] ] = 1 f[a[i]]=1 f[a[i]]=1则表示 a [ i ] a[i] a[i]是可以用前面的面值表示出来的,跳过,否则从 a [ i ] a[i] a[i]循环到 m a x n maxn maxn( a [ i ] a[i] a[i]中的最大值),判断 f [ j − a [ i ] ] f[j-a[i]] f[j−a[i]]能否被表示,可以的话就让 f [ j ] = 1 f[j]=1 f[j]=1即可
#include
using namespace std;
int n,a[105],f[25005],ans,maxn;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(f,0,sizeof(f));
maxn=0;
ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxn=max(maxn,a[i]);
}
sort(a+1,a+n+1);
f[0]=1;
for(int i=1;i<=n;i++)
{
if(f[a[i]]) continue;
ans++;
for(int j=a[i];j<=maxn;j++) f[j]|=f[j-a[i]];
}
printf("%d\n",ans);
}
return 0;
}
这题就不那么简单了,容易想到的是用树形DP,同时题面要求的是“最短长度最长”,就是明显的二分答案
那么我们取 m i n ( a [ i ] ) min(a[i]) min(a[i])为左边界, Σ i = 1 n a [ i ] \Sigma_{i=1}^{n}a[i] Σi=1na[i]为右边界进行二分答案
用两个数组 f [ i ] f[i] f[i]和 g [ i ] g[i] g[i]分别表示以 i i i为根节点的子树中有多少条长度 > = m i d >=mid >=mid,去掉满足条件的路径后从 i i i往上连最长的长度
在转移时将当前节点所有子节点的 g [ i ] g[i] g[i]加上 w [ i ] w[i] w[i]后加入一个 m u l t i s e t multiset multiset中,因为我们之后要先将长度满足 > = m i d >=mid >=mid的加到答案中,所以需要从大到小排序,而且不能去重,所以 m u l t i s e t multiset multiset是一个很好的选择
加入后从后往前扫 m u l t i s e t multiset multiset的元素,如果 > = m i d >=mid >=mid加到答案(即 f f f数组中),否则退出循环
然后我们从前往后扫 m u l t i s e t multiset multiset中的元素,然后用 l o w e r lower lower_ b o u n d bound bound在 m u l t i s e t multiset multiset中找能够与它配对的元素,找不到的话就用这个元素来更新 g [ i ] g[i] g[i],这样就可以得到最优解了
#include
using namespace std;
int cnt,fst[50005],nxt[100005],to[100005],w[100005];
int n,m,l=2147400000,r,mid,ans,f[50005],g[50005];
multiset <int> s;
multiset <int>::iterator it;
void AddEdge(int u,int v,int c)
{
to[++cnt]=v;
nxt[cnt]=fst[u];
fst[u]=cnt;
w[cnt]=c;
}
void Dfs(int u,int faz)
{
for(int i=fst[u];i;i=nxt[i])
{
int v=to[i];
if(v==faz) continue;
Dfs(v,u);
f[u]+=f[v];
}
for(int i=fst[u];i;i=nxt[i])
{
int v=to[i];
if(v==faz) continue;
s.insert(g[v]+w[i]);
}
while(!s.empty())
{
int now=*s.rbegin();
if(now>=mid)
{
it=s.find(now);
f[u]++;
s.erase(it);
}
else break;
}
while(!s.empty())
{
int now=*s.begin();
s.erase(s.begin());
it=s.lower_bound(mid-now);
if(it==s.end()) g[u]=now;
else
{
f[u]++;
s.erase(it);
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
AddEdge(x,y,z);
AddEdge(y,x,z);
l=min(l,z);
r+=z;
}
while(l<=r)
{
mid=l+r>>1;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
Dfs(1,0);
if(f[1]>=m)
{
ans=max(ans,mid);
l=mid+1;
}
else r=mid-1;
}
printf("%d",ans);
return 0;
}