1. 程式人生 > 實用技巧 >2020 年百度之星·程式設計大賽 - 初賽一

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\n",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\n",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\n",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\n",dp[a][b]);
    }
    return 0;
}

這裡有個比較玄學的問題,就是maxn的大小,如果maxn大於等於1005就會T(我習慣開1005),換句話說maxn的值只能取1001,1002,1003,1004(親身試過的T^T)

這是1005的那一發,當時還以為這不是動歸的題,,,

然後最後時間快截止了改了下maxn的大小改成了1002