震惊,某蒟蒻竟苟对一道题

又是三道题

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

猜你喜欢

转载自blog.csdn.net/enesama/article/details/79371082