中石油 暑期集训个人赛 DP部分

可恶的C题

问题 C: 母鸡下蛋

时间限制: 1 Sec   内存限制: 128 MB
提交: 196   解决: 44
[ 提交][ 状态][ 讨论版]

题目描述

鸡国中的母鸡最擅长下蛋了,MGMG 是鸡国中一只以下蛋产量高而闻名全鸡国的母鸡。 
鸡国专供下蛋的 n 个鸡窝呈一字排列在鸡国的“下蛋中心”,从左到右依次编号为 1 到n。每个鸡窝都有一个最大可下蛋的量,其中第 i 个鸡窝的最大可下蛋量为 ci 。有时候由于MGMG 产量实在太大而无法在一个鸡窝中下完所有的蛋,不得不转移到隔壁的鸡窝继续下蛋,如果隔壁的鸡窝还是不能让它下完所有的蛋,则 MGMG 继续转移,直到下完所有的蛋,或者向“下蛋中心”管理员投诉“鸡窝数量实在太少了,我一只鸡的下蛋量都装不下!”。 
为了节省转移时所耗费的体力,请你编程帮助 MGMG 找若干个连续的鸡窝(个数尽量少),让它能下完所有的蛋。 

输入

输入共 2 行。 
第 1 行输入两个整数 n 和 t,表示“下蛋中心”有 n 个可供下蛋的鸡窝,MGMG 一次总共要下 t 个鸡蛋。 
第 2 行 n 个正整数 ci (1≤i≤n),依次表示第 i 个鸡窝最大可下蛋量为 ci 个。 

输出

输出 1 行一个整数或一个单词。当输出整数时表示让 MGMG 下完所有的蛋至少需要几个连续的鸡窝。当 MGMG 用完所有的鸡窝都无法下完所有的蛋时,MGMG 表示非常愤怒,输出单词“Angry”(不包含双引号,注意大小写)。 

样例输入

5 4
1 2 1 2 3

样例输出

2

C题模拟肯定会超时,题意类似于求最大间隙问题。不妨用一个数组来储存前i项和,用一个数x来记录左下标,枚举前i项和,当i大于x的时候,求出差值,用差值跟母鸡的蛋比较,再记录最小i-x的差值,最后输出差值。若一开始蛋大于所有窝的和输出angry.  由于差值不断增大,所以最后求出的i-x的差值肯定是最小。线性时间。


代码实现:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

int main()
{
	int dp[100005],i,j,k,n,t,x,len;
	while(cin>>n>>t)
	{
		len=0x3f3f3f3f;
		memset(dp,0,sizeof(dp)); //清空数组 
		for(i=1;i<=n;i++)
		{
			cin>>x;
			dp[i]=dp[i-1]+x;  //前i项和 
		}
		if(t>dp[n])
		{
			cout<<"Angry"<<endl; //无法生那么多蛋 
			continue;
		}
		x=0; //左下标 
		for(i=1;i<=n;i++)  //枚举前i项和 
		{
			while(i>x&&dp[i]-dp[x]>=t) 
			{
				len=min(len,i-x);
				x++;  //下标后移 
			}
		}
		cout<<len<<endl;
	}
	return 0;
}


可恶的H题

问题 H: wtaxi

时间限制: 1 Sec   内存限制: 128 MB
提交: 58   解决: 29
[ 提交][ 状态][ 讨论版]

题目描述

话说小 x 有一次去参加比赛,虽然学校离比赛地点不太远,但小 x 还是想坐出租车去。大学城的出租车总是比较另类,有“拼车”一说,也就是说,你一个人坐车去,还是一堆人一起,总共需要支付的钱是一样的(每辆出租上除司机外最多坐下 4 个人)。刚好那天同校的一群 Oier 在校门口扎堆了,大家果断决定拼车去赛场。
问题来了,一辆又一辆的出租车经过,但里面要么坐满了乘客,要么只剩下一两个座位,众 Oier 都觉得坐上去太亏了,小 x 也是这么想的。
假设 N 位 Oier 准备拼车,此时为 0 时刻,从校门到目的地需要支付给出租车师傅 D 元(按车次算,不管里面坐了多少 Oier),假如 S 分钟后恰能赶上比赛,那么 S 分钟后经过校门口的出租车自然可以忽略不计了。现在给出在这 S 分钟当中经过校门的所有的 K 辆出租车先后到达校门口的时间 Ti 及里面剩余的座位 Zi(1 <= Zi <= 4),Oier 可以选择上车几个人(不能超过),当然,也可以选择上 0 个人,那就是不坐这辆车。
俗话说,时间就是金钱,这里小 x 把每个 Oier 在校门等待出租车的分钟数等同于花了相同多的钱(例如小 x 等待了 20 分钟,那相当于他额外花了 20 元钱)。
在保证所有 Oier 都能在比赛开始前到达比赛地点的情况下,聪明的你能计算出他们最少需要花多少元钱么?

输入

每组数据以四个整数 N , K , D , S 开始,具体含义参见题目描述。
接着 K 行,表示第 i 辆出租车在第 Ti 分钟到达校门,其空余的座位数为 Zi(时间按照先后顺序)。
N <= 100,K <= 100,D <= 100,S <= 100,1 <= Zi <= 4,1<= T(i) <= T(i+1) <= S

输出

对于每组测试数据,输出占一行,如果他们所有人能在比赛前到达比赛地点,
则输出一个整数,代表他们最少需要花的钱(单位:元),否则请输出“impossible”。

样例输入

2 2 10 5
1 1
2 2

样例输出

14

典型的dp,可以用二维数组,dp[i][j]表示i辆车装j个人时花的时间,也可以用一维数组,dp【i】表示第i个人的最小钱数。一维dp类似于背包问题。

贴一下二维dp的代码,附赠一维dp的题解地址:点击打开链接


代码实现:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

int main()
{
	int n,k,d,s,dp[105][105],i,j,o,a,b; //dp[i][j]表示i辆车装j个人时花的时间 
	while(cin>>n>>k>>d>>s)
	{
		memset(dp,0x3f3f3f3f,sizeof(dp));
		dp[0][0]=0;
		for(i=1;i<=k;i++)
		{
			for(j=0;j<=n;j++)
			dp[i][j]=dp[i-1][j];  //初始化数组 
			
			cin>>a>>b;
			
			for(j=0;j<=n;j++) //枚举人 
			for(o=0;o<=b;o++) //枚举坐多少人 
			if(j>=o)
			dp[i][j]=min(dp[i-1][j-o]+o*a+d,dp[i][j]);
		}
		if(dp[k][n]!=0x3f3f3f3f)
		cout<<dp[k][n]<<endl;
		else
		cout<<"impossible"<<endl;
	}
	return 0;
}

可恶的G题

问题 G: 【动态规划】cirs

时间限制: 1 Sec   内存限制: 128 MB
提交: 124   解决: 48
[ 提交][ 状态][ 讨论版]

题目描述

Czyzoiers 都想知道小 x 为什么对鸡蛋饼情有独钟。经过一番逼问,小 x 道出了实情:因为他喜欢圆。最近小 x 又发现了一个关于圆的有趣的问题:在圆上有2N 个不同的点,小 x 想用 N 条线段把这些点连接起来(每个点只能连一条线段),使所有的线段都不想交,他想知道这样的连接方案有多少种?

输入

有且仅有一个正整数 N(N≤3000)。

输出

要求的方案数(结果 mod 100000007)。

样例输入

2

样例输出

2

提示

1 号点与 2 号点连接:2 种。
1 号点与 4 号点连接:1 种。
1 号点与 6 号点连接:2 种。



传说中的dp,卡特兰数直接套公式就可以得到。由于才学疏浅,硬生生把公式推了出来。可以看示例,他将圆分成了两份,其中两份都是前面得到的。

代码实现:

#include<iostream>
#include<algorithm>

using namespace std;

int main()
{
	long long n,i,a[3005],j;
	
	a[0]=1;a[1]=1;a[2]=2;
	for(i=3;i<3005;i++)
	for(j=1;j<=i;j++)
	a[i]=(a[i]+a[i-j]*a[j-1])%100000007;
		
	while(cin>>n)
	{
		cout<<a[n]<<endl;
	}
	return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值