又是三道题
party
题目描述:
在M公司里,每个人只有一个直属上司(除了boss)。这个公司举办派对,每个人可以给派对带来一定的欢乐值,但是每个人不能和自己的上司同时参加这个派对,求派对的最大欢乐值。
输入:
第一行n表示公司有n个人。
第二行n个数,表示每个人的上司是谁,如果这个人的上司为0,说明这个人是boss。
第三行n个数,表示每个人的欢乐值为wi。
输出:
一行一个数表示最大欢乐值。
样例输入:
6
0 1 1 1 4 4
1 1 1 1 1 1
样例输出:
4
解释:2 3 5 6 同时出席。
数据规模:
对于30%的数据,n<=20。
对于100%的数据,n<= 1000000,0<=w[i]<=1000。
然后会发现这道题是一道简单的树形dp模板题
只需要随便感性建建图就行了
#include<bits/stdc++.h>
using namespace std;
int dp[1000005][2];
int shu,head[1000005],next[1000005],to[1000005],tot,n,boss;
void add(int x,int y)
{
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void work(int x)
{
if(!head[x])
{
return;
}
for(int i=head[x];i;i=next[i])
{
int y=to[i];
work(y);
dp[x][1]+=dp[y][0];
dp[x][0]+=max(dp[y][0],dp[y][1]);
}
}
int read()
{
char c;
int x;
for(c=getchar();c>'9'||c<'0';c=getchar());
x=c-'0';
for(c=getchar();c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
return x;
}
int main()
{
freopen("party.in","r",stdin);
freopen("party.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
{
shu=read();
add(shu,i);
if(shu==0)
boss=i;
}
for(int i=1;i<=n;i++)
{
shu=read();
dp[i][1]=shu;
}
work(boss);
cout<<max(dp[1][1],dp[1][0]);
return 0;
}
/*
6
0 1 1 1 4 4
1 1 1 1 1 1
*/
然后就开始了噩梦之旅
接着一道同样的树状dp
可是我做错了
就很难受
treasure
题目描述:
小a可以攻打m座城堡,攻打每个城堡有不同的宝物,但是在攻打有些城堡前,需要攻打另外的城堡。小a想知道,能获得的最多宝物是多少?
输入:
第一行两个数,n,m。分别表示有n个城堡,可以攻打m个。
接下来n行每行两个数a,b,分别表示在攻打第i个城堡前需要攻打a,攻打后获得b的宝物。
输出:
一行一个数ans表示可以获得的最大宝物数量。
样例输入
3 2
0 1
0 2
0 3
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
0 0
样例输出:
5
13
数据规模:
对于30%的数据,n<=20,m<=20。
对于100%的数据,n<=500,m<=500,b[i]<=1000。
这道题仍然是树状dp
然后感性的玄学状态转移
不知为何必须把点权的循环写错了
后面莫名其妙的在同学的帮助下学完的点权和边权版本
就很痛苦
#include<bits/stdc++.h>
using namespace std;
int n,m,shu,value[5005],to[5005],next[5005],head[5005],tot,ans,size[5005],dp[505][505],shu1,shu2,w[5005];
void add(int x,int y)
{
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void work(int x)
{
size[x]=1;
if(head[x]==0)
{
return;
}
for(int i=head[x];i;i=next[i])
{
int y=to[i];
work(y);
size[x]+=size[y];
for(int j=size[x];j>=0;j--)
for(int k=1;k<=min(size[y],j-1);k++)
{
dp[x][j]=max(dp[x][j-k]+dp[y][k],dp[x][j]);
}
}
}
int main()
{
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&shu1,&shu2);
add(shu1,i);
dp[i][1]=shu2;
}
work(0);
cout<<dp[0][m+1];
return 0;
}
/*
3 2
0 1
0 2
0 3
*/
以及最后还有一道最长公共子序列的题
array
题目描述:
给定两个长度为n的排列p1和p2,求它们的最长公共子序列。
输入:
第一行一个数n。
接下来两个n个数分别表示p1和p2。
输出:
一个数表示最长子序列的长度。
样例输入:
3
123
213
样例输出:
2
解释及说明:
共有两种方案,分别为子序列为13和子序列为23.
数据规模:
对于30%的数据,n<=2000.
对于100%的数据,n<=100000
这道题有一个特点
他是从1开始n个连续数的不同排列
长度也是相同
所以这道题是在第一组数中建立一个数到下标的映射
映射到第二组数中
就变成了一个求最长上升子序列长度的问题
最后用一下nlogn的算法就可以了
然而今天还是不想写昨天的题就很难受
于是今天又留下一道题bzoj4472
我觉得可以开始苟一下期望dp的题了
比如baoj4872和hdu4405