2013腾讯编程马拉松初赛(3月20日)
1 第一题 小Q系列故事——屌丝的逆袭
表示这道题基本没什么算法,学过计算机语言的应该都能搞定吧。
2 第二题 小明系列故事——买年货
这道题直接用01背包问题就可以解决了,只是除了钱的限制,还有积分的限制和免费的情况,就是这点在调试程序的时候出了点小问题,总是wa。状态可以定义为dp[x][y][z],x表示钱的,y表示积分的,z表示免费的状态,然后其它的和背包问题差不多了,只是维数到了3维。
1 #include <stdio.h> 2 #include <string.h> 3 4 #define max(a,b) a > b ? a : b 5 int n, v1, v2, k; 6 typedef struct _thing 7 { 8 int a; 9 int b; 10 int val; 11 }thing_t; 12 13 int main(void) 14 { 15 thing_t data[101]; 16 int ans; 17 int dp[101][101][6]; 18 int i,j,y,x, temp; 19 while (scanf("%d%d%d%d", &n, &v1, &v2, &k) != EOF) 20 { 21 for (i = 1; i <= n; i ++) 22 scanf("%d%d%d", &data[i].a, &data[i].b, &data[i].val); 23 memset(dp, -1, sizeof(dp)); 24 ans = 0; 25 dp[0][0][0] = 0; 26 for (i = 1; i <= n; i ++) 27 { 28 for (j = v1; j >= 0; j --) 29 { 30 for (y = v2; y >= 0; y --) 31 { 32 for (x = k; x >= 0; x --) 33 { 34 temp = -1; 35 if (j - data[i].a >= 0 && dp[j - data[i].a][y][x] != -1) 36 { 37 if( temp < dp[j - data[i].a][y][x] + data[i].val)38 temp = dp[j - data[i].a][y][x] + data[i].val; 39 } 40 if (y - data[i].b >= 0 && dp[j][y - data[i].b][x] != -1) 41 { 42 if( temp < dp[j][y - data[i].b][x] + data[i].val) 43 temp = dp[j][y - data[i].b][x] + data[i].val; 44 } 45 if (x - 1 >= 0 && dp[j][y][x - 1] != -1) 46 { 47 if( temp < dp[j][y][x - 1] + data[i].val) 48 temp = dp[j][y][x - 1] + data[i].val; 49 } 50 dp[j][y][x] = max(temp, dp[j][y][x]); 51 if (ans < dp[j][y][x]) 52 ans = dp[j][y][x]; 53 } 54 } 55 } 56 } 57 printf("%d\n", ans); 58 } 59 return 0; 60 }
3 第三题 吉哥系列故事——临时工计划
这个题目就直接用dp了,dp[x]表示前x天内获得的最大工资数,状态方程为:
dp[x] = max{dp[y] + c[y + 1][x]} ,其中c[y + 1][x]表示某份从第y + 1天到第x天的工作的工资,1 <= y <= x - 1 且 c[y + 1][x]不为0。
1 #include <stdio.h> 2 #include <string.h> 3 4 int t; 5 int m,n; 6 int data[101][101]; 7 int ans[101]; 8 9 int main(void) 10 { 11 int i, j, k, s, e, c; 12 scanf("%d", &t); 13 for (i = 1; i <= t; i ++) 14 { 15 scanf("%d%d", &m, &n); 16 memset(data, 0 ,sizeof(data)); 17 for (j = 1; j <= n; j ++) 18 { 19 scanf("%d%d%d", &s, &e, &c); 20 if (data[s][e] < c) 21 data[s][e] = c; 22 } 23 ans[0] = 0; 24 for (j = 1; j <= m; j ++) 25 { 26 ans[j] = ans[j - 1]; 27 for (k = 1; k <= j; k ++) 28 if (data[k][j] && ans[k - 1] + data[k][j] > ans[j]) 29 ans[j] = ans[k - 1] + data[k][j]; 30 } 31 printf("%d\n", ans[m]); 32 } 33 return 0; 34 }
思路:根据题目选的3个人互不认识或者都认识则关系相同,从这种关系相同的反面来看就是3个人只有两个认识,最后一个人不认识,所以可以求这种反面情况的个数,对于第i个人,可以选他自己和他的朋友一个即a中情况,剩余一个人选他不认识的人(即非朋友)即n-a-1中情况,所以sum +=a*(n-a-1),sum表示总情况数,由于自己和朋友计算的时候会多算一次,所以最后要sum /= 2才是反面的情况总数。
1 #include <stdio.h> 2 3 int main(void) 4 { 5 int t, n, b, i, j, all; 6 double sum; 7 8 scanf("%d", &t); 9 for (i = 0; i < t; i ++) 10 { 11 scanf("%d", &n); 12 all = n * (n - 1) * (n - 2) / 6; 13 sum = 0.0; 14 for (j = 0; j < n; j ++) 15 { 16 scanf("%d", &b); 17 sum += b * (n - b - 1); 18 } 19 sum /= 2; 20 sum /= all; 21 printf("%.3lf\n", 1 - sum); 22 } 23 return 0; 24 }
首先算出B队最终的得分sb,再算出要赢B队至少要得的分sum = sb + 1 - a(a为A队当前的得分),然后穷举满足后面得分不小于sum的所有情况。
1 #include <stdio.h> 2 3 int a, b, t; 4 __int64 ans; 5 int sum; 6 7 __int64 f(int start) /*计算阶乘*/ 8 { 9 __int64 ans = 1; 10 11 while (start > 1) 12 { 13 ans *= start; 14 start --; 15 } 16 return ans; 17 } 18 19 int main(void) 20 { 21 int i,j; 22 long long c_w, c_d; 23 24 while (scanf("%d%d%d", &a, &b, &t) != EOF) 25 { 26 c_w = t / 15; 27 if (c_w % 2 == 0) 28 c_w = t / 30; 29 else 30 c_w = t / 30 + 1; 31 c_d = t / 30; 32 sum = b + c_d + 1 - a; 33 ans = 0; 34 for (i = 0; i <= c_w; i ++) 35 for (j = 0; j <= c_w - i; j ++) 36 if (i * 1 + j * 2 + (c_w - i - j) * 3 >= sum) 37 ans += f(c_w) / (f(i) * f(j) * f(c_w - i - j)); 38 printf("%I64d\n", ans); 39 } 40 return 0; 41 }