这次比赛共5题,其实都不难,如果我状态很好,运气很好的话,做3个不是问题,这次比赛各种dp,真惊了。。
比赛完了看看rank,被各种大一的给虐的不成样了,我们学校齐心协力最后居然才出了第一题和第三题。。。
时常被大一虐虐总是好的。。
1、HDU 小Q系列故事——屌丝的逆袭
1001 小Q系列故事——屌丝的逆袭
Time Limit: 0.1 Seconds Memory Limit: 65536K
毕业于普通本科的小Q一直自称是资深屌丝,不仅学校不知名,甚至他自己在这个普通学校也是默默无闻——直到临近毕业的时候,班里5朵金花中的2位甚至从没和他说过话!
谁又能想到,如此不起眼的小Q在历经重重面试环节后,竟然如愿以偿加入了心仪已久的腾讯公司!消息刚刚传开的那几天,这在他们班甚至整个学院都是讨论的热门话题,如果这时候你还表示不知道小Q是谁,你都会被大家当作怪物的。
正所谓野百合也有春天,屌丝也有逆袭的那一天!
刚到腾讯大厦上班的那几天,小Q眼中的一切都是那么新鲜,连每天见到的前台MM在他眼中都胖的那么可爱。小Q就这样在紧张与兴奋的情绪中度过了一天又一天,每天即勤奋认真又小心翼翼,很希望能给主管留下个好印象,以免失去这来之不易的工作机会。
一段时间以后,随着对工作环境以及同事的熟悉,小Q逐渐放松下来,在工作间隙,他细细观察了自己的工作环境,发现整个工作室是一个N行M列的矩形布局,或者是因为屌丝的本性逐步暴露,他还暗自给每个同事在心里进行了魅力值评分(为区别男女,男生一律用负整数表示,女生一律用正整数表示)。
现在,小Q把所有人的数据记录下来,并且这样定义一个位置的价值:
1、一个位置的价值只和其上下左右四个邻居的魅力值有关(对于靠边的位置,只考虑其存在的邻居);
2、如果某位置的邻居和该位置主人性别不同,则总分加上邻居魅力值的绝对值,否则减去;
3、对周围所有邻居的数据处理后,最终的得分即为这个位置的最终得分,得分越高,则该位置越好;
现在你能帮助小Q计算一下哪里才是最佳位置吗?
Input
输入包含多组测试数据;
每组测试数据的第一行包含2个整数N和M,表示工作室的布局是N行M列;
接下来的N行,每行有M个整数,分别表示对应位置员工的魅力值数据Ki,正整数表示女生的魅力值,负整数表示男生的魅力值;
N和M为0的时候表示输入数据结束。
[Technical Specification]
N<=20
M<=20
-100<=Ki<=100
请计算并输出最佳位置的行列号以及对应的得分,如果得分最高的位置有多个,则请输出行号最小的那个,行号还相同的话,再比较列号,只输出列号最小的那个即可。
Sample Input
2 3
5 -4 3
-6 3 7
0 0
Sample Output
1 2 11这题就是水。找一遍就可以得出答案了。不过我居然wa了,因为没看到题目要求mn为0的时候结束。。我一个EOF就赤裸裸的wa了。。。居然用了半个小时才敲出来。。果然是好久没做题了啊。。。。一直搞个sae搞的不行了都。。。
- #include <iostream>
- #include <cstdio>
- #include <string>
- #include <cmath>
- using namespace std;
- const int maxn = 25;
- int n, m;
- bool judge(int x, int y)
- {
- if (x<0 || y<0 || x>=n || y>=m)
- return false;
- return true;
- }
- int main()
- {
- int ans[maxn][maxn], rec[maxn][maxn];
- bool flag[maxn][maxn];
- int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
- while (scanf("%d %d", &n, &m), m || n)
- {
- int i, j;
- memset(ans, 0, sizeof(ans));
- memset(rec, 0, sizeof(rec));
- memset(flag, false, sizeof(flag));
- for (i=0; i<n; i++)
- {
- for (j=0; j<m; j++)
- {
- scanf("%d", &rec[i][j]);
- if (rec[i][j] < 0) flag[i][j] = true;
- }
- }
- int max = 0, ansi, ansj;
- for (i=0; i<n; i++)
- {
- for (j=0; j<m; j++)
- {
- int k;
- for (k=0; k<4; k++)
- {
- int x = i + dir[k][0];
- int y = j + dir[k][1];
- if (judge(x, y))
- {
- if (flag[i][j]^flag[x][y]) ans[i][j] += abs(rec[x][y]);
- else ans[i][j] -= abs(rec[x][y]);
- }
- }
- if (ans[i][j] > max)
- {
- max = ans[i][j];
- ansi = i;
- ansj = j;
- }
- // printf("%d ", ans[i][j]);
- }
- // puts("");
- }
- printf("%d %d %d\n", ansi+1, ansj+1, max);
- }
- return 0;
- }
2、HDU 4501 小明系列故事——买年货
1002 小明系列故事——买年货
Time Limit: 2.0 Seconds Memory Limit: 65536K
春节将至,小明要去超市购置年货,于是小明去了自己经常去的都尚超市。
刚到超市,小明就发现超市门口聚集一堆人。用白云女士的话说就是:“那家伙,那场面,真是人山人海,锣鼓喧天,鞭炮齐呤,红旗招展。那可真是相当的壮观啊!”。好奇的小明走过去,奋力挤过人群,发现超市门口贴了一张通知,内容如下:
值此新春佳节来临之际,为了回馈广大顾客的支持和厚爱,特举行春节大酬宾、优惠大放送活动。凡是都尚会员都可用会员积分兑换商品,凡是都尚会员都可免费拿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
124
是个挺麻烦的多维背包,不过也挺基础,我还是能做出来的,大约用了1h就搞定了,而且1a,早知道比赛就做这道题了。。
还可以优化,实在懒了不过。。。
- #include <iostream>
- #include <string>
- using namespace std;
- #define max(a,b) ((a)>(b)?(a):(b))
- struct Commodity
- {
- int a, b, val; //价钱、积分、实际价值
- }com[105];
- int n, v1, v2, k;
- int dp[105][105][105][6];
- int main()
- {
- while (scanf("%d %d %d %d", &n, &v1, &v2, &k) != EOF)
- {
- int i, j, m, q;
- for (i=1; i<=n; i++)
- {
- scanf("%d %d %d", &com[i].a, &com[i].b, &com[i].val);
- }
- memset(dp, 0, sizeof(dp));
- int ans = -1;
- for (i=1; i<=n; i++)
- {
- for (m=0; m<=v1; m++)
- {
- for (j=0; j<=v2; j++)
- {
- for (q=0; q<=k; q++)
- {
- dp[i][m][j][q] = dp[i-1][m][j][q];
- if (com[i].a <= m) dp[i][m][j][q] = max(dp[i][m][j][q], dp[i-1][m-com[i].a][j][q] + com[i].val);
- if (com[i].b <= j) dp[i][m][j][q] = max(dp[i][m][j][q], dp[i-1][m][j-com[i].b][q] + com[i].val);
- if (q>0) dp[i][m][j][q] = max(dp[i][m][j][q], dp[i-1][m][j][q-1] + com[i].val);
- ans = max(ans, dp[i][m][j][q]);
- }
- }
- }
- }
- printf("%d\n", ans);
- }
- return 0;
- }
3 、 HDU 4502 吉哥系列故事——临时工计划
1003吉哥系列故事——临时工计划
Time Limit: 1.0 Seconds Memory Limit: 32768K
俗话说一分钱难倒英雄汉,高中几年下来,吉哥已经深深明白了这个道理,因此,新年开始存储一年的个人资金已经成了习惯,不过自从大学之后他不好意思再向大人要压岁钱了,只能把唯一的希望放到自己身上。可是由于时间段的特殊性和自己能力的因素,只能找到些零零碎碎的工作,吉哥想知道怎么安排自己的假期才能获得最多的工资。
已知吉哥一共有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
对于每组数据,输出吉哥可获得的最高工资数。
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就行其实。。。我好久没敲题了。。。背包的模样都忘了,于是翻出白皮书来找背包。。。这要是正规比赛得多丢人啊。。。
提交了好几次都是wa,看到州州过了,剩余时间不多了,于是就不敲这道题了,转敲第五题,21号上午,改了改就过了,下面是我的代码。
- #include <cstdio>
- #include <string>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- #define max(a, b) ((a)>(b)?(a):(b))
- const int maxw = 1005;
- int m, n;
- int dp[105];
- struct Work
- {
- int s, t, m;
- }work[maxw];
- int cmp(Work a, Work b)
- {
- return (a.t < b.t);
- }
- int main()
- {
- int T;
- scanf("%d", &T);
- while (T--)
- {
- memset(dp, 0, sizeof(dp));
- scanf("%d %d", &m, &n);
- int i, j;
- for (i=0; i<n; i++)
- {
- scanf("%d %d %d", &work[i].s, &work[i].t, &work[i].m);
- }
- sort(work, work+n, cmp);
- // puts("");
- for (i=0; i<n; i++)
- {
- if (work[i].t > m) continue;
- int tmp = dp[work[i].s-1] + work[i].m;
- for (j=work[i].t; j<=m; j++)
- {
- if (dp[j] < tmp) dp[j] = tmp;
- // printf("%d ", dp[i][j]);
- }
- // puts("");
- }
- printf("%d\n", dp[m]);
- }
- return 0;
- }
4、HDU 4503 湫湫系列故事——植树节【转】
1004 湫湫系列故事——植树节
Time Limit: 0.5 Seconds Memory Limit: 32768K
今天是一年一度的植树节,腾讯幼儿园要求每个老师在班里选出几个小朋友一起去野外种植小树苗,根据学校的整体安排,湫湫老师的班里要选出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
本题思考起来有点难。
但是反过来考虑,就是3个关系不完全一样的。就是3个点有1条或者两条变的。
所以累加a[i]*(n-1-a[i])的话,就刚好把不符合的数了两次,除于2就是不符合的了。
总数是C(n,3)然后就容易出来了。
- #include <stdio.h>
- #include <string.h>
- #include <iostream>
- #include <math.h>
- #include <map>
- #include <string>
- #include <algorithm>
- #include <set>
- #include <vector>
- #include <queue>
- using namespace std;
- int a[1005];
- int main()
- {
- int T;
- int n;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d",&n);
- for(int i=0;i<n;i++)
- {
- scanf("%d",&a[i]);
- }
- int ans=0;
- int tol=n*(n-1)*(n-2)/6;
- for(int i=0;i<n;i++)ans+=a[i]*(n-a[i]-1);
- ans/=2;
- ans=tol-ans;
- printf("%.3lf\n",(double)ans/tol);
- }
- return 0;
- }
5、 HDU 4504 威威猫系列故事——篮球梦【转】
1005 威威猫系列故事——篮球梦
Time Limit: 0.1 Seconds Memory Limit: 32768K
威威猫十分迷恋篮球比赛,是忠实的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
这题有点类似母函数的感觉,用DP求解系数。
网上大牛一篇
- #include <stdio.h>
- #include <string.h>
- #include <iostream>
- #include <math.h>
- #include <map>
- #include <string>
- #include <algorithm>
- #include <set>
- #include <vector>
- #include <queue>
- using namespace std;
- long long dp[30][100];
- void init()
- {
- memset(dp,0,sizeof(dp));
- //for(int i=0;i<=60;i++)dp[0][i]=d[1][i]=0;
- dp[1][1]=dp[1][2]=dp[1][3]=1;
- for(int i=2;i<=20;i++)
- {
- for(int j=1;j<=60;j++)
- {
- if(j>1)dp[i][j]+=dp[i-1][j-1];
- if(j>2)dp[i][j]+=dp[i-1][j-2];
- if(j>3)dp[i][j]+=dp[i-1][j-3];
- }
- }
- }
- int main()
- {
- int A,B,T;
- init();
- while(scanf("%d%d%d",&A,&B,&T)==3)
- {
- int t=T/15;
- int tA=(t+1)/2;
- if(tA==0)
- {
- if(A>B)printf("1\n");
- else printf("0\n");
- continue;
- }
- int tB=t-tA;
- B+=tB;
- int tmp=B-A+1;
- if(tmp<0)tmp=0;
- long long ans=0;
- for(int i=tmp;i<=60;i++)
- {
- ans+=dp[tA][i];
- }
- printf("%I64d\n",ans);
- }
- return 0;
- }
大牛石其宁的一篇
- #include<stdio.h>
- #include<string.h>
- #define N 600
- int main()
- {
- int a,b,t,i,j,k,n,sub,xb,ta,tb,c1[N],c2[N];
- while(scanf("%d %d %d",&a,&b,&t)!=EOF)
- {
- n=t/15;
- tb=n/2;
- ta=n-tb;
- sub=b-a+tb-ta;
- memset(c1,0,sizeof(c1));
- c1[0]=1;
- for(i=0;i<ta;i++)
- {
- memset(c2,0,sizeof(c2));
- for(j=0;j<3;j++)
- {
- for(k=j;k<N;k++)
- c2[k]+=c1[k-j];
- }
- memcpy(c1,c2,sizeof(c2));
- }
- if(sub<0)
- xb=0;
- else
- xb=sub+1;
- __int64 ans=0;
- for(i=xb;i<N;i++)
- ans+=c1[i];
- printf("%I64d\n",ans);
- }
- return 0;
- }