小明系列故事——买年货
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1480 Accepted Submission(s): 636
Problem Description
春节将至,小明要去超市购置年货,于是小明去了自己经常去的都尚超市。
刚到超市,小明就发现超市门口聚集一堆人。用白云女士的话说就是:“那家伙,那场面,真是人山人海,锣鼓喧天,鞭炮齐呤,红旗招展。那可真是相当的壮观啊!”。好奇的小明走过去,奋力挤过人群,发现超市门口贴了一张通知,内容如下:
值此新春佳节来临之际,为了回馈广大顾客的支持和厚爱,特举行春节大酬宾、优惠大放送活动。凡是都尚会员都可用会员积分兑换商品,凡是都尚会员都可免费拿k件商品,凡是购物顾客均有好礼相送。满100元送bla bla bla bla,满200元送bla bla bla bla bla...blablabla....
还没看完通知,小明就高兴的要死,因为他就是都尚的会员啊。迫不及待的小明在超市逛了一圈发现超市里有n件他想要的商品。小明顺便对这n件商品打了分,表示商品的实际价值。小明发现身上带了v1的人民币,会员卡里面有v2的积分。他想知道他最多能买多大价值的商品。
由于小明想要的商品实在太多了,他算了半天头都疼了也没算出来,所以请你这位聪明的程序员来帮帮他吧。
Input
输入包含多组测试用例。
每组数据的第一行是四个整数n,v1,v2,k;
然后是n行,每行三个整数a,b,val,分别表示每个商品的价钱,兑换所需积分,实际价值。
[Technical Specification]
1 <= n <= 100
0 <= v1, v2 <= 100
0 <= k <= 5
0 <= a, b, val <= 100
Ps. 只要钱或者积分满足购买一件商品的要求,那么就可以买下这件商品。
Output
对于每组数据,输出能买的最大价值。
详细信息见Sample。
Sample Input
5 1 6 1
4 3 3
0 3 2
2 3 3
3 3 2
1 0 2
4 2 5 0
0 1 0
4 4 1
3 3 4
3 4 4
Sample Output
12
4
//背包DP
#include<iostream>
#include<cstring>
using namespace std;
short dp[101][101][6];
int v1Arr[101], v2Arr[101],val[101];
int main()
{
int n,v1,v2,k;
while(cin>>n>>v1>>v2>>k)
{
for(int i=1;i<=n;i++)
cin>>v1Arr[i]>>v2Arr[i]>>val[i];
for(int num=1;num<=n;num++)
for(int i=v1;i>=0;i--)
for(int j=v2;j>=0;j--)
for(int p=k;p>=0;p--)
{
int tmp=0;
if(i-v1Arr[num]>=0) tmp = max(tmp, dp[i-v1Arr[num]][j][p]+val[num]);
if(j-v2Arr[num]>=0) tmp = max(tmp, dp[i][j-v2Arr[num]][p]+val[num]);
if(p-1>=0) tmp = max(tmp, dp[i][j][p-1]+val[num]);
dp[i][j][p] = max(dp[i][j][p], (short)tmp);
}
cout<<dp[v1][v2][k]<<endl;
memset(dp,0,sizeof(dp));
}
return 0;
}
吉哥系列故事——临时工计划
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0
Problem Description
俗话说一分钱难倒英雄汉,高中几年下来,吉哥已经深深明白了这个道理,因此,新年开始存储一年的个人资金已经成了习惯,不过自从大学之后他不好意思再向大人要压岁钱了,只能把唯一的希望放到自己身上。可是由于时间段的特殊性和自己能力的因素,只能找到些零零碎碎的工作,吉哥想知道怎么安排自己的假期才能获得最多的工资。
已知吉哥一共有m天的假期,每天的编号从1到m,一共有n份可以做的工作,每份工作都知道起始时间s,终止时间e和对应的工资c,每份工作的起始和终止时间以天为单位(即天数编号),每份工作必须从起始时间做到终止时间才能得到总工资c,且不能存在时间重叠的工作。比如,第1天起始第2天结束的工作不能和第2天起始,第4天结束的工作一起被选定,因为第2天吉哥只能在一个地方工作。
现在,吉哥想知道怎么安排才能在假期的m工资数(第m+天内获得最大的1天吉哥必须返回学校,m天以后起始或终止的工作是不能完成的)。
Input
第一行是数据的组数T;每组数据的第一行是2个正整数:假期时间m和可做的工作数n;接下来n行分别有3个正整数描述对应的n个工作的起始时间s,终止时间e,总工资c。
[Technical Specification]
1<=T<=1000
9<m<=100
0<n<=1000
s<=100, e<=100, s<=e
c<=10000
Output
对于每组数据,输出吉哥可获得的最高工资数。
Sample Input
1
10 5
1 5 100
3 10 10
5 10 100
1 4 2
6 12 266
Sample Output
102
//直接dp超时,将工作以结束日期分类,再dp,时间是o(m+n)
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> stail[110];
vector<int> swage[110];
int dp[110];
int main()
{
int t,m,n;
cin>>t;
while(t--)
{
cin>>m>>n;
int pstart,pend,w;
for(int i=0;i<=m;i++)
{
stail[i].clear();
swage[i].clear();
dp[i]=0;
}
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&pstart,&pend,&w);//此处用scanf ,用cin会超时!!!
if(pstart>m || pend>m) continue;
if(pstart>pend) continue;
if(pstart<1) continue;
stail[pend].push_back(pstart);
swage[pend].push_back(w);
}
for(int i=1;i<=m;i++)
{
dp[i] = dp[i-1];
int sz = stail[i].size();
for(int j=0;j<sz;j++)
{
dp[i] = max(dp[i], dp[ stail[i][j]-1 ] + swage[i][j] );
}
}
cout<<dp[m]<<endl;
}
return 0;
}
湫湫系列故事——植树节
Time Limit: 1000/500 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0
Problem Description
今天是一年一度的植树节,腾讯幼儿园要求每个老师在班里选出几个小朋友一起去野外种植小树苗,根据学校的整体安排,湫湫老师的班里要选出3个小朋友。 已知湫湫的班里共有n个孩子,每个孩子有Bi个朋友(i从1到n),且朋友关系是相互的,如果a小朋友和b小朋友是朋友,那么b小朋友和a小朋友也一定是好朋友。为了选择的公平性,湫湫老师会随机抽取3个小朋友出来(每个人被抽到的概率相同),但是她很希望这3个小朋友之间的关系完全相同,湫湫老师想请你帮她算算抽到的3个小朋友正好关系相同的概率是多少?
PS. 关系相同就是指要么3个人互相是好朋友,要么3个人互相都不是好朋友。
Input
输入数据第一行是一个整数T(1<=T<=1000),表示输入数据的组数;每组数据的第一行是一正整数n表示孩子的总数(2<n<=1000),第二行有n个数Bi (i从1到n),分别代表每个小朋友的朋友的个数。
Output
对于每组数据,请输出抽到的3个小朋友关系相同的概率,结果保留3位小数。
Sample Input
1
5
3 3 3 3 4
Sample Output
0.400
//问题的转化,求一条边和两条边的情况
#include <cstdio>
#include <iostream>
using namespace std;
int num[1005];
int main()
{
int T, n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int tot = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d", &num[i]);
tot += num[i] * (n - 1 - num[i]);
}
tot >>= 1; // 每个结果被计算了两次
int t = n * (n-1) * (n-2) / 6;
printf("%.3f\n", 1.0 * (t - tot) / t);
}
return 0;
}
威威猫系列故事——篮球梦
Time Limit: 300/100 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0
Problem Description
威威猫十分迷恋篮球比赛,是忠实的NBA球迷,他常常幻想自己那肥硕的身躯也能飞起扣篮。另外,他对篮球教练工作也情有独钟,特别是对比赛的战术,投篮选择方面也是很有研究,下面就是威威猫研究过的一个问题:
一场NBA篮球比赛总共48分钟,假如我们现在已经知道当前比分 A:B,A代表我方的比分,B代表对方的比分,现在比赛还剩下t秒时间。我们简单的认为双方各自进攻一次的时间皆固定为15秒(不到15秒则进攻不得分),且为交替进攻,即我方进攻一次,接着对方进攻,依次循环。
进攻有三种选择方式:(这里不考虑命中率)
1、造犯规,(假设都两罚一中)得1分;
2、中距离投篮 得2分;
3、三分球 得3分。
为了简化问题,假设在对方回合,由于我方防守比较好,只让对手得1分,且为固定,即对方的进攻回合就为每回合得1分。现在比赛进入最后关头,接下来第一个回合是我方进攻,现在威威猫想要知道教练有多少种不同的选择能使我方可能赢得比赛(可能的意思就是不考虑命中率的情况)。
Input
输入有多组数据(不超过250组);
每组数据包含3个整数A,B和t,其中A和B 表示当前的比分(0 <= A, B <= 200),t表示还剩多少时间(单位秒 0 <= t <= 600)。
Output
请输出可行的方案数,每组数据输出占一行。
Sample Input
88 90 50
Sample Output
6
Hint
样例解析:
当前比分是88:90,还剩50秒则对方还最多有一次进攻机会(最后5秒进攻不成功),我方有两次,对方的最终得分将是91,我方至少在两回合中拿到4分才能胜利,所以所有方案数是6种,即:
第一球 第二球
1 3
2 2
2 3
3 1
3 2
3 3
#include<iostream>
using namespace std;
long long scr[130];//注意溢出,只能longlong型
int main()
{
int a,b,t,i,j;
while(cin>>a>>b>>t){
int achances = (t/15 + 1)/2;
if(achances == 0)
{
if(a>b) cout<<1<<endl;
else cout<<0<<endl;
continue;
}
int minscores = b + (t/15 - achances) +1 -a;
if(minscores <= 0) minscores = 1;
int maxscores = 3*achances;
if(maxscores < minscores){
cout<<0<<endl;
continue;
}
scr[1]=scr[2]=scr[3]=1;
for(i=4;i<=maxscores;i++)
scr[i]=0;
for(i=2;i<=achances;i++)
for(j=maxscores;j>=1;j--)
scr[j]=(j>1?scr[j-1]:0) + (j>2?scr[j-2]:0) + (j>3?scr[j-3]:0);
long long result=0;
for(i=minscores;i<=maxscores;i++)
result += scr[i];
cout<<result<<endl;
}
return 0;
}