2013腾讯编程马拉松初赛第〇场

小明系列故事——买年货

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 374    Accepted Submission(s): 162


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
 

Source
2013腾讯编程马拉松初赛第〇场(3月20日)



#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

struct GOODS {int a, b, val;} g[110];
int n, v1, v2, m;
int dp[102][102][102][6];

int main()
{
    while(scanf("%d%d%d%d",&n,&v1,&v2,&m) != EOF)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d%d%d",&g[i].a, &g[i].b, &g[i].val);

        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++)
        for(int j = 0; j <= v1; j++)
        for(int k = 0; k <= v2; k++)
        for(int s = 0; s <= m; s++)
        {
            dp[i][j][k][s] = max(dp[i-1][j][k][s], dp[i][j][k][s]);

            if(j >= g[i].a)
                dp[i][j][k][s] = max(dp[i-1][j-g[i].a][k][s] + g[i].val, dp[i][j][k][s]);

            if(k >= g[i].b)
                dp[i][j][k][s] = max(dp[i-1][j][k-g[i].b][s] + g[i].val, dp[i][j][k][s]);

            if(s >= 1)
                dp[i][j][k][s] = max(dp[i-1][j][k][s-1] + g[i].val, dp[i][j][k][s]);
        }
        printf("%d\n", dp[n][v1][v2][m]);
    }
    return 0;
}






吉哥系列故事——临时工计划

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 780    Accepted Submission(s): 285




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


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

#define MAXN 1010
int T, m, n;
struct JOB {int s, t, e;} job[MAXN];
int dp[MAXN];

int cmp(const void* a, const void* b)
{
    return ((JOB*)a)->t - ((JOB*)b)->t;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&m,&n);
        for(int i = 1; i <= n; i++)
            scanf("%d%d%d",&job[i].s,&job[i].t,&job[i].e);

        qsort(job+1, n, sizeof(job[0]), cmp);
        memset(dp, 0, sizeof(dp));

        for(int i = 1; i <= m; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(job[j].t > i) break;
                dp[i] = max(dp[i], job[j].e + dp[job[j].s-1]);
            }
        }
        printf("%d\n", dp[m]);
    }
    return 0;
}




湫湫系列故事——植树节

Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 269    Accepted Submission(s): 170


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
 

Source
2013腾讯编程马拉松初赛第〇场(3月20日)


分析:关系相同就是指要么3个人互相是好朋友,要么3个人互相都不是好朋友,亦即:三个点要么两两之间有一条边,要么三个点之间全都没有边。

正面考虑太困难了。所以从反面考虑:三个点之间有一条边或者两条边。

当任意选取一个点i的时候,剩下的n-1个点可以分为两个集合:{与i相连的} = b[i], {与i不相连的} = n - 1 - b[i]

所以,从两个集合中各选取一个点,再加上i点,这三个点之间要么有一条边要么有两条边,即b[i] * (n-1-b[i])种

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int C(int n, int m)
{
    if(n <= m || m == 0) return 0;
    m = min(n - m, m);

    int ret = 1;
    for(int i = 1; i <= m; i++)
        ret = ret * (n - i + 1) / i;
    return ret;
}

int main()
{
    int T, n;
    int b[1010];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d", &n);

        for(int i = 0; i < n; i++)
            scanf("%d", &b[i]);

        int cnt = 0;
        for(int i = 0; i < n; i++)
            cnt += b[i] * (n - b[i] - 1);
        cnt /= 2;

        double total = (double)C(n, 3);
        printf("%.3lf\n", (total - cnt) / total);
    }
    return 0;
}



威威猫系列故事——篮球梦

Time Limit: 300/100 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 980    Accepted Submission(s): 243


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
 

Source
2013腾讯编程马拉松初赛第〇场(3月20日)


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

long long dp[22][66];

void cal()
{
    memset(dp, 0, sizeof(dp));
    dp[1][1] = dp[1][2] = dp[1][3] = 1;
    for(int i = 2; i < 22; i++)
    {
        for(int j = 1; j < 66; j++)
        {
            if(j - 1 >= 1) dp[i][j] += dp[i-1][j-1];
            if(j - 2 >= 1) dp[i][j] += dp[i-1][j-2];
            if(j - 3 >= 1) dp[i][j] += dp[i-1][j-3];
        }
    }
}

int main()
{
    cal();
    int a, b, t;
    while(scanf("%d%d%d",&a,&b,&t) != EOF)
    {
        int c = t / 15;
        int ca = (c + 1) / 2;
        int cb = c / 2;

        if(ca == 0)
        {
            if(a <= b) printf("0\n");
            else printf("1\n");
        }
        else
        {
            int mn = b + cb + 1 - a ; //最少得分
            if(mn < 0) mn = 0;
            int mx = ca * 3; //最多得分

            long long res = 0;
            for(int i = mn; i <= mx; i++)
                res += dp[ca][i];
            printf("%I64d\n",res); //printf("%lld\n",res);错了一晚上!!坑呀!
        }
    }
    return 0;
}



你可能感兴趣的:(2013腾讯编程马拉松初赛第〇场)