杭电“计算机学院大学生程序设计竞赛(2015’11)”题解【1-3】

1001搬砖

Problem Description
小明现在是人见人爱,花见花开的高富帅,整天沉浸在美女环绕的笙歌妙舞当中。但是人们有所不知,春风得意的小明也曾有着一段艰苦的奋斗史。
那时的小明还没剪去长发,没有信用卡没有她,没有24小时热水的家,可当初的小明是那么快乐,尽管甚至没有一把破木吉他…
之所以快乐,是因为那时的小明心怀逆袭梦想。有一天,小明为了给他心目中的女神买生日礼物,来到了某建筑工地搬砖挣钱。就在这个时候,工地上又运来了一卡车的砖,包工头让小明把卡车卸下来的那堆砖分成一块一块的(要求任何2块转都要分开)。作为资深搬运工,小明总是每次将一堆砖分为两堆,这时候,所消耗的体力是分完之后两堆砖数目的差值。
现在,已知卡车运来的砖的数目,请告诉小明最少要花费多少体力才能完成包工头所要求的任务呢?

Input
输入数据第一行是一个正整数T(T<=100),表示有T组测试数据。
接下来T行每行一个正整数N(N<=10000000),表示卡车运来的砖块的数目。

Output
对于每组数据,请输出小明完成任务所需的最少体力数。

Sample Input

4
5

Sample Output

0
2

题意概述

把一个数a分成b+c,需要消耗abs(b-c)的精力。现需要把一个数n无限次数的分解成n个1,问:最少需要消耗多少精力?

题目分析

首先考虑到对于1,不需要分解,消耗为0。
对于2可以分解为1+1,消耗为0。
对于3可以分解为1+2,消耗为1的消耗+2的消耗+abs(1-2)。
……
动态规划:
设f(n)为分解n时的最小消耗,当n为偶数时,f(n)=2*f(n/2);当n为基数时,f(n)=f(n/2)+f(n/2+1)+1。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

#define INF 0x7ffffff
#define LOCAL
using namespace std;
int ans[10000001];
int main(){
    #ifdef LOCAL
        freopen("input.in","r",stdin);
    #endif // LOCAL
    int t;
    for(int i=0;i<10000001;i++){
        ans[i] = 0;
    }
    ans[1] = 0;
    ans[2] = 0;
    for(int i=3;i<10000001;i++){
            if(i%2!=0) ans[i] = ans[i/2]+ans[i/2+1]+1;
            else ans[i] = 2*ans[i/2];
    }
    cin>>t;
    while(t--){
        int a;
        cin>>a;
        cout<<ans[a]<<endl;
    }

    return 0;
}

or

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

#define INF 0x7ffffff
#define LOCAL
using namespace std;
int f(int n){
    if(n==1||n==2){
        return 0;
    }
    if(n%2)
        return f(n/2)+f(n/2+1)+1;
    else
        return 2*f(n/2);
}
int main(){
    #ifdef LOCAL
        freopen("input.in","r",stdin);
    #endif // LOCA
    int t;
    cin>>t;
    while(t--){
        int a;
        cin>>a;
        cout<<f(a)<<endl;
    }
    return 0;
}

1002投币洗衣机

Problem Description
如今大学生的生活条件越来越好了,近期,内蒙某高校在每个寝室楼都添置了一台投币洗衣机。
小明作为经常参加训练的ACM队员,非常忙(Lan)碌(Duo),当然非常乐意把衣服丢给洗衣机解决啦。根据要洗的衣服数量,投币洗衣机每次需要投入2-4 枚硬币。
小明是一个非常容易出汗的男生,夏天就要到了,每天都要洗澡,所以也就有大量衣服需要洗。
小明是这么制定投币洗衣机计划的:当屯积的衣服数量大于等于a且小于b的时候,他就会马上全部拿去给洗衣机洗,并且投入2枚硬币;当屯积的衣服数量大于等于b且小于c的时候,他就会马上全部拿去给洗衣机洗,并且投入3枚硬币;当屯积的衣服数量大于等于c的时候,他就会马上全部拿去给洗衣机洗,并且投入4枚硬币。其他细节见样例。
现在知道,小明过去n 天每天换下的衣服数量v件,需要你帮忙计算出小明在过去这段时间洗衣服一共花了多少钱。

Input
输入包含多组测试数据。
每组数据第一行是4个正整数 n (1<=n<=10000) 、a 、b 、c (1<=a

题意概述

简单的条件判断

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

#define INF 0x7ffffff
#define LOCAL
using namespace std;
int arr[10001];
int main(){
    #ifdef LOCAL
        freopen("input.in","r",stdin);
    #endif // LOCAL
    int n,a,b,c;
    while(cin>>n>>a>>b>>c){
        for(int i=1;i<=n;i++){
            cin>>arr[i];
        }
        int totle = 0;
        int money = 0;
        for(int i=1;i<=n;i++){
            totle+=arr[i];
            if(totle>=a&&totle<b){
                money+=2;
                totle = 0;
            }else if(totle>=b&&totle<c){
                money+=3;
                totle = 0;
            }else if(totle>=c){
                money+=4;
                totle = 0;
            }else{
                continue;
            }
        }
        cout<<money<<endl;
    }
    return 0;
}

1003掷色子

Problem Description
Nias与Ains都特别喜欢玩骰子,而且都自以为比对方玩得更溜。
终于有一天,他们决定用骰子来一决高下!
一般的骰子玩法已经不足以体现他们的水平了,于是他们自创了一套玩法来PK:
首先,每人掷3个骰子;之后,可以选择其中一个骰子重新掷(当然也可以放弃这一步),最后,比较投掷结果的大小,结果大的那方获胜,一样的话为平局。
大小比较规则为:
三个一样数字的骰子称为三条;两个一样数字的骰子称为对子;只有一个数字的骰子成为散牌。三条>对子>散牌。当双方结果都为三条时,直接比较三条数字的大小;都有对子时,先比较对子数字的大小,若相同,再比较剩下的骰子的数字的大小;都只有散牌时,先比较最大的数字的大小,若相同,再比较次大的数字的大小,还相同,最后比较最小的数字的大小。
现在Nias已经投了3个骰子,还剩一次机会可以选择其中一个骰子重新投(或不选),而且他已经知道了Ains的最后投掷结果,求Nias获胜的概率有多大。

Input
输入数据第一行为一个整数T,表示有T组测试数据。
接下来T行,每行6个1~6的整数,前三个表示Nias第一次的投掷结果,后三个表示Aias最终的投掷结果。

Output
请输出Nias获胜的概率,结果保留3位小数,每组输出占一行。

Sample Input

4
2 3 5 3 3 4
3 3 1 2 2 2
6 2 1 5 4 3
1 2 3 4 4 1

Sample Output

0.333
0.167
1.000
0.000

题意概述

甲乙两人各有三个色子,掷完后,甲可以选择任意选择一个色子重新掷或不掷。问甲胜的概率有多大?(其中三条大于对子大于散牌)

题意分析

模拟题,如果甲本来就大于乙,则胜率为1.000;若甲本来不大于乙,则对三个色子分别模拟投掷,每个模拟投掷的点数为1-6,对每种可能的结果进行判断是否能胜乙。取三个色子中胜率最大的那个。

代码

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
int judge_type(int *a){
    sort(a,a+3);
    if(a[0]==a[2])
        return 3;
    else if(a[0]==a[1]||a[1]==a[2])
        return 2;
    else
        return 1;
}
bool judge_win(int *a,int *b){
    int a_type = judge_type(a);
    int b_type = judge_type(b);
    if(a_type==b_type){
        sort(a,a+3);
        sort(b,b+3);
        int a_value = a[2]*100+a[1]*10+a[0];
        int b_value = b[2]*100+b[1]*10+b[0];
        if(a_type!=2){
            return a_value>b_value;
        }else{
            int a_double= a[1];
            int a_single = a[0]==a[1]?a[2]:a[0];
            int b_double = b[1];
            int b_single = b[0]==b[1]?b[2]:b[0];
            if(a_double>b_double||(a_double==b_double&&a_single>b_single)) return true;
            else return false;
        }
    }else{
        return a_type>b_type;
    }
}
int nias[3],ains[3];
int main()
{
    int t;
    cin>>t;
    while(t--){
        scanf("%d%d%d%d%d%d",nias,nias+1,nias+2,ains,ains+1,ains+2);
        if(judge_win(nias,ains)){
            printf("1.000\n");
        }else{
            double ans = 0;
            int p[3];
            for(int i=0;i<3;i++){
                int win =0 ;
                for(int j=1;j<=6;j++){
                    p[0] = nias[(i+1)%3];
                    p[1] = nias[(i+2)%3];
                    p[2] = j;
                    if(judge_win(p,ains))
                        win++;
                }
                ans = max(ans,1.0*win/6.0);
            }
            printf("%.3lf\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值