6.1考试

1:接苹果:

【问题描述】

奶牛喜欢吃苹果。约翰有两棵苹果树,有 N 只苹果会从树上陆续落下。如果掉苹果的时候,贝西在那棵树下,她就能接住苹果。贝西一开始在第一棵树下。在苹果掉落之前,她有足够的时间来回走动,但她很懒,最多只愿意移动 K 次。请计算一下她最多可以接住几只苹果。

 

【输入】

第一行:两个整数 N K1 ≤ N ≤ 1000; 1 ≤ K ≤ 30
i + 1 行有一个整数 Ti,表示第 i 只苹果从哪棵树上掉落,1 表示从第一棵树,2 表示从第二棵树

 

 

【输出】

单个整数:表示能接住的最大苹果数量

 

【输入输出样例1】

bcatch.in

bcatch.out

7 2
2
1
1
2
2
1
1

6

解释
先待在第一棵树下接住两个,然后移动到第二棵树下接住两个,再返回第一棵树接住最后两个

 

考试最开始的时候,我就一直想用一维DP来求解,最可怕的不是这个,而是我居然十分(脑残)地想出来了!30分的悲惨结局,后来才想到是三维的DP,用f[i][j][k]表示第i个苹果的时候,用了j次移动,k是用来表示位置的(不能用j的基偶性来表示,不然会炸)。程序:

#include<bits/stdc++.h>
using namespace std;
int n,k,a[1100],f[1100][31][3];
int main()
{
	scanf("%d%d",&n,&k);
	a[0]=1;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int j=0;j<=k;j++)
	{
		for(int i=1;i<=n;i++)
		{
			if(a[i]==1)
			{
				f[i][j][1]=max(f[i-1][j-1][2]+1,f[i-1][j][1]+1);
				f[i][j][2]=f[i-1][j][2];
			}
			else
			{
				f[i][j][2]=max(f[i-1][j-1][1]+1,f[i-1][j][2]+1);
				f[i][j][1]=f[i-1][j][1];
			}
		}
	}
	cout<<max(f[n][k][2],f[n][k][1]);
	return 0;
}

但是在老师讲的时候,使用二维DP来写得:

 

 

 

没事懂很好理解。

 

 

 

T2;奶牛飞盘队:

 

【问题描述】

农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘队.

他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤100000).约翰要选出1只或多于1只奶牛来参加他的飞盘队.

约翰比较迷信,他的幸运数字是F,所以他要求队伍的总能力必须是F的倍数。请帮他算一下,符合这个要求的队伍组合有多少?由于这个数字很大,只要输出答案除以10^8 的余数就可以了。

【输入】

第一行:两个用空格分开的整数:NF1 ≤ N ≤ 20001 ≤ F ≤ 1000

第二行到N + 1行:第i + 1行有一个整数R i ,表示第i头奶牛的能力,1 ≤ R i ≤ 10^5

【输出】

 

【输入输出样例1】

fristeam.in

fristeam.out

4 5 
1 
2 
8 
2 

3

 

FJ has four cows whose ratings are 1, 2, 8, and 2. He will only accept a team whose rating sum is a multiple of 5.

FJ can pair the 8 and either of the 2's (8 + 2 = 10), or he can use both 2's and the 1 (2 + 2 + 1 = 5).

 

我在考试的时候,十分“机智”地想了一个用前缀和来一个一个减去的方法,这样就可以最短时间内求出来了,当然这只是我当时的想法,后来我发现会有后效性,就一直加位置,结果就拿到了10分的搞分。

正解:

第i只牛有两种可能性,要还是不要,所以,这个我们可以往0/1背包上考虑。因为我们要求的是F的整数倍的方案数,我们只考虑这种可能性无法满足最优子结构,按照我们常见的套路,我们显然要把 当前组成的累加和对Fmod的值进行存储。

 

程序:

#include<bits/stdc++.h>
using namespace std;
int n,a[2100],f,dp[2100][2100];
int mod=100000000;
int main()
{
	scanf("%d%d",&n,&f);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		int t=a[i]%f;
		if(!t) t=f;
		dp[i][t]=1;
		if(i==1) continue;
		for(int j=1;j<=f;j++)
		{
			t=(j+a[i])%f;
			if(!t)t=f;
			dp[i][t]+=dp[i-1][j];
			dp[i][j]+=dp[i-1][j];
			dp[i][t]=dp[i][t]%mod;
			dp[i][j]=dp[i][j]%mod;
		}
	}
	cout<<dp[n][f];
	return 0;
}

 

 

 

T3股票市场:

【问题描述】

 

【输入输出样例1】

stock.in

stock.out

2 3 10 
10 15 15 
13 11 20 

24

 

我一看到这题,就先想到了贪心,然后就想到了这样的程序,后来去写T4了,就没有管:

#include<bits/stdc++.h>
using namespace std;
int s,d,m,a[51][51],maxx,maxxi,t,num;
int main()
{
	scanf("%d%d%d",&s,&d,&m);
	for(int i=1;i<=s;i++)
	{
		for(int j=1;j<=d;j++) scanf("%d",&a[i][j]);
	}
	for(int j=1;j<d;j++)
	{
		maxx=-999999999;
		for(int i=1;i<=s;i++)
		{
			t=a[i][j+1]-a[i][j];
			if(t>maxx&&m>=a[i][j]) maxx=t,maxxi=i;
		}
		num=m/a[maxxi][j];
		m=m%a[maxxi][j];
		m+=num*a[maxxi][j+1];
	}
	cout<<m;
	return 0;
}

当然这不是正解。

其实每天的利润就相当于今天买了,明天卖掉,然后再买。(这谁会这么买啊)。

因此第一天买的股票,第三天卖出去,可以当成第一天买的,第二天卖出去,然后在卖,第三天再卖出去,这样就可以把每一天的利润给分开了。这样我们得到一个贪心算法,依次考虑每相邻两天,前一天买入后一天全部卖出所能得到的最大收益,而这正是个简单的背包问题:股票就是物品,花费就是前一天的价格,收益就是后一天的价格,背包就是资金。

 

因此对于每一天,就是一个完全背包,重量为当天的价格,价值为该股票到第二天的利润;可以用f[i][j]表示前i个股票用j块钱的最大利润。DP方程:f[i][j]=f[i-1][j-a[i]]+a[i+1]-a[i];

。。先鸽l

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 奶牛飞盘队 时限:1000ms 内存限制:10000K 总时限:3000ms 描述: Farmer John 想从他的N只奶牛(1<=N<=2000)选出若干组成一支飞盘队,N只奶牛依次编号为1..N,每只奶牛根据其飞盘的技能排名为R_i,(1<=R_i<=100,000)。由于Farmer John的幸运数字是F(1<=F<=1000), 因此,他想让他的队伍中奶牛的排名之和是F的倍数。现在Farmer John知道,他有多少种选择的方式。由于这个数十分大,因此只用输出这个数 模( mod )100,000,000.。 输入: 第一行两个数字N和F。 接下来的N行每行有一个数字代表第R_i. 输出: 只有一行,输出FJ 组队方案数 mod 100,000,000的值(对100,000,000取余数 )。 输入样例: 4 5 1 2 8 2 输出样例: 3 提示: 注:样例中Farmer John 有4只奶牛,排名依次为 1, 2, 8, and 2. ,然而FJ只会选排名之和为5的倍数的队伍。 来源: USACO月赛 2. 判素数 时限:100ms 内存限制:10000K 总时限:1000ms 描述: 给出一个数N(2<=N<=10000),判定它是否为素数。 素数:一个大于等于2的数,除了1和它本身,再没有其他的整数能将其整除的数叫素数。 输入: 从标准输入输入一个整数。 输出: 若给定数为素数,向标准输出输出“Yes”,否则,输出“No”。 输入样例: 997 输出样例: Yes 提示: 从2开始,到N-1,对N进行试除,若存在某个数能将N整除,说明N为非素数。若不存在任何的整数能将其整除,说明N试素数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值