2020 年百度之星·程序设计大赛

Drink 

传送门

 Accepts: 1896
 
 Submissions: 4596
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
Problem Description

我们有 nn 种不同的饮料,每种饮料有无限多瓶,第 ii 种饮料一瓶提供 x[i]x[i] 毫升的水分,包含 y[i]y[i] 卡路里。

现在我们需要选择一种饮料一直喝,直到补充了至少 mm 毫升的水分,我们想使得摄入的卡路里总和最小。请求出这个最小值。

一旦打开一瓶饮料,就一定要喝完。

Input

第一行一个整数 test(1 le test le 100)test(1test100) 表示数据组数。

对于每组数据,第一行两个整数 n, m(1 le n le 100, 1 le m le 10000)n,m(1n100,1m10000)。

接下来 nn 行,每行两个整数 x[i], y[i](1 le x[i], y[i] le 100)x[i],y[i](1x[i],y[i]100)。

Output

对于每组数据,一行一个整数表示答案。

Sample Input
2
1 10
3 3
2 10
3 3
2 1
Sample Output
12
5

解题思路:因为n种饮料种每种饮料的补充水分x和和包含的卡路里都不同,所以从头到尾遍历看哪种饮料消耗的卡路里最少(注意这里是 一种饮料一直喝)
我们便可以的到如下代码:
#include<cstdio>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,t;
int x[105],y[105];
int main(void)
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i)
        {
            scanf("%d%d",&x[i],&y[i]);
        }
        int sum=INF;//初始化总卡路里
        for(int i=0;i<n;++i)
        {
            if(m%x[i])//如果不能被整除
            sum=min(sum,m/x[i]*y[i]+y[i]);
            else//能被整除
            sum=min(sum,m/x[i]*y[i]);
        }
        printf("%d
",sum);
    }
    
    return 0;
}

开始没看到一种饮料一直喝,还以为是完全背包问题(不会写),结果后来发现是个大水题 T_T

GPA

传送门

 Accepts: 1554
 
 Submissions: 3947
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
Problem Description

小沃沃一共参加了 4 门考试,每门考试满分 100 分,最低 0 分,分数是整数。

给定四门考试的总分,请问在最优情况下,四门课绩点的和最高是多少?

分数与绩点之间的对应关系如下:

95~100 4.3

90~94 4.0

85~89 3.7

80~84 3.3

75~79 3.0

70~74 2.7

67~69 2.3

65~66 2.0

62~64 1.7

60~61 1.0

0~59 0

Input

第一行一个正整数 test(1 le test le 401)test(1test401) 表示数据组数。 接下来 testtest 行,每行一个正整数 xx 表示四门考试的总分 (0 le x le 400)(0x400)。

Output

对于每组数据,一行一个数表示答案。答案保留一位小数。

Sample Input
2
0
400
Sample Output
0.0
17.2


解题思路:仔细分析其实我们不需要哪个分数区间,我们只需要区间的最小的值代表那个绩点,也就是说 95~100 -> 4.3 在最优的情况下,其实我们不需要在意在区间取值,95就能表示绩点4.3
总共有四个成绩,十一个分数段,那么就有两种循环方式,第一个是对分数段循环,第二个就是对四个成绩循环。
解法1:
#include<cstdio>
#include<iostream>
using namespace std;
int t,x,key;
int main(void)
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&x);
        double sum=0,sum2;
        for(int a=0;a<5;++a)
        {
            if(a*95>x)
            break;
            for(int b=0;b<5;++b)
            {
                if(a*95+b*90>x)
                break;
                for(int c=0;c<5;++c)
                {
                    if(a*95+b*90+c*85>x)
                    break;
                    for(int d=0;d<5;++d)
                    {
                        if(a*95+b*90+c*85+d*80>x)
                        break;
                        for(int e=0;e<5;++e)
                        {
                            if(a*95+b*90+c*85+d*80+e*75>x)
                            break;
                            for(int f=0;f<5;++f)
                            {
                                if(a*95+b*90+c*85+d*80+e*75+f*70>x)
                                break;
                                for(int g=0;g<5;++g)
                                {
                                    if(a*95+b*90+c*85+d*80+e*75+f*70+g*67>x)
                                        break;
                                    for(int h=0;h<5;++h)
                                    {
                                        if(a*95+b*90+c*85+d*80+e*75+f*70+g*67+h*65>x)
                                            break;
                                        for(int i=0;i<5;++i)
                                        {
                                            if(a*95+b*90+c*85+d*80+e*75+f*70+g*67+h*65+i*62>x)
                                            break;
                                            for(int j=0;j<5;++j)
                                            {
                                                key=a*95+b*90+c*85+d*80+e*75+f*70+g*67+h*65+i*62+j*60;
                                                sum2=a*4.3+b*4.0+c*3.7+d*3.3+e*3.0+f*2.7+g*2.3+h*2.0+i*1.7+j*1.0;
                                                if(key<=x)
                                                {
                                                    sum=max(sum,sum2);
                                                }
                                                else
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        printf("%.1lf
",sum);
    }
    return 0;
}

解法2:

#include<cstdio>
#include<iostream>
using namespace std;
int a[11]={95,90,85,80,75,70,67,65,62,60,0};
double b[11]={4.3,4.0,3.7,3.3,3.0,2.7,2.3,2.0,1.7,1.0,0};
int main(void)
{
    
    int x,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&x);
        double sum=0;
        for(int i=0;i<11;++i)
        {
            for(int j=0;j<11;++j)
            {
                for(int k=0;k<11;++k)
                {
                    for(int l=0;l<11;++l)
                    {
                        int s=a[i]+a[j]+a[k]+a[l];
                        if(s<=x)
                        {
                            sum=max(sum,b[i]+b[j]+b[k]+b[l]);
                        }
                    }
                }
            }    
        }
        printf("%.1lf
",sum);
    }
    return 0;
}

Dec 

传送门

 Accepts: 1284
 Submissions: 4572
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 32768/32768 K (Java/Others)
Problem Description

初始有 a, ba,b 两个正整数,每次可以从中选一个大于 1 的数减 1,最后两个都会减到 1,我们想知道在过程中两个数互质的次数最多是多少。

Input

第一行一个正整数 test(1 le test le 1000000)test(1test1000000) 表示数据组数。

接下来 test 行,每行两个正整数 a, b(1 le a, b le 1000)a,b(1a,b1000)。

Output

对于每组数据,一行一个整数表示答案。

Sample Input
1
2 3
Sample Output
4

样例解释 2 3 -> 1 3 -> 1 2 -> 1 1


解题思路:这道题开始可能会有人觉得这是数学题目,其实不然,再通过仔细阅读题目之后,我们能发现一个问题数据有1e6组而且a和b刚好小于等于1e3,这不就明显摆着动态规划嘛
由于每次从a,b两个数中选一个然后减一,那么我们就能把这个问题拆成小问题,a和b的互质的数就去找 a-1和b互质的数,a和b-1互质的数,然后选出最大的值赋给dp[a][b],但是要注意a和b本身就互质的情况
由于1和其他数字都互质所以我们可以初始化dp[i][1]=dp[1][i]=i。
状态转移方程式为:
dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j])
&&if(gcd(i+1,j+1)==1)
dp[i+1][j+1]++;
我们可以得到如下代码:
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1002
int t,a,b;
int dp[maxn][maxn];
int main(void)
{
    for(int i=1;i<maxn;++i)
    dp[i][1]=dp[1][i]=i;
    for(int i=1;i<maxn;++i)
    {
        for(int j=1;j<maxn;++j)
        {
            if(__gcd(i+1,j+1)==1)
            {
                dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j])+1;
            }
            else
            {
                dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
            }
        }
    }
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&a,&b);
        printf("%d
",dp[a][b]);
    }
    return 0;
}

这里有个比较玄学的问题,就是maxn的大小,如果maxn大于等于1005就会T(我习惯开1005),换句话说maxn的值只能取1001,1002,1003,1004(亲身试过的T^T)

 这是1005的那一发,当时还以为这不是动归的题,,,

然后最后时间快截止了改了下maxn的大小改成了1002

原文地址:https://www.cnblogs.com/Mangata/p/13344614.html