2020 年百度之星·程序设计大赛 - 初赛一 题解

Drink
http://acm.hdu.edu.cn/showproblem.php?pid=6743
枚举每种饮料即可



#include
#include
using namespace std;
int t,n,m;
int x[10005],y[10005];
int dp[10005];
int main()
{
    int minans;
    scanf("%d",&t);
    while(t--)
    {
        minans=1e9;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
        for(int i=1;i<=n;i++)
        {
            if((m+x[i]-1)/x[i]*y[i]<minans) minans=(m+x[i]-1)/x[i]*y[i];
        }
        printf("%d\n",minans);
    }
    return 0;
}


GPA
http://acm.hdu.edu.cn/showproblem.php?pid=6744
考虑到GPA只有11种情况,11^4暴力枚举每种情况即可

#include
#include
using namespace std;
int pz[23][2];
int x,ans,t;
int main()
{
    pz[0][0]=0;pz[0][1]=0;
    pz[1][0]=60;pz[1][1]=10;
    pz[10][0]=95;pz[10][1]=43;
    pz[9][0]=90;pz[9][1]=40;
    pz[8][0]=85;pz[8][1]=37;
    pz[7][0]=80;pz[7][1]=33;
    pz[6][0]=75;pz[6][1]=30;
    pz[5][0]=70;pz[5][1]=27;
    pz[4][0]=67;pz[4][1]=23;
    pz[3][0]=65;pz[3][1]=20;
    pz[2][0]=62,pz[2][1]=17;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        scanf("%d",&x);
        for(int i1=0;i1<=10;i1++)
        for(int i2=0;i2<=10;i2++)
        for(int i3=0;i3<=10;i3++)
        for(int i4=0;i4<=10;i4++)
        if(pz[i1][0]+pz[i2][0]+pz[i3][0]+pz[i4][0]<=x)
        {
            if(pz[i1][1]+pz[i2][1]+pz[i3][1]+pz[i4][1]>=ans) ans=pz[i1][1]+pz[i2][1]+pz[i3][1]+pz[i4][1];
        }
        printf("%d.%d\n",ans/10,ans%10);
    }
    return 0;
}

Dec
http://acm.hdu.edu.cn/showproblem.php?pid=6745
乍一看是个数论,其实是个DP,注意到x,y范围都是1000,而询问次数有1e6次,最好的办法显然是计算出每种x,y组合对应的情况后打表。

a n s [ 1 ] [ 1 ] = 1 ans[1][1]=1 ans[1][1]=1
a n s [ i ] [ j ] = m a x ( a n s [ i − 1 ] [ j ] , a n x [ i ] [ j − 1 ] ) + ( g c d ( i , j ) = = 1 ) ans[i][j]=max(ans[i-1][j],anx[i][j-1])+(gcd(i,j)==1) ans[i][j]=max(ans[i1][j],anx[i][j1])+(gcd(i,j)==1)



#include
#include
using namespace std;
int ans[1005][1005];
inline int gcd(int x,int y){return x?(gcd(y%x,x)):y;}
int main()
{
    for(int i=1;i<=1000;i++) ans[i][1]=ans[1][i]=i;
    for(int i=2;i<=1000;i++)
    for(int j=2;j<=1000;j++)
    {
        ans[i][j]=max(ans[i-1][j],ans[i][j-1])+(gcd(i,j)==1);
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",ans[a][b]);
    }
    return 0;
}


Civilization
http://acm.hdu.edu.cn/showproblem.php?pid=6746

分别计算下从每个点开始需要的最少回合数,再计算从出发点到达这个点需要的回合数,加起来取最小值即可。



#include
#include
using namespace std;
int a[505][505],x,y,n;
int ans[505][505];
int cot[5];
int queue[233];
int minans;
void BfsAndCalc(int x,int y)
{
    int cou=1,pro,round=0;
    cot[1]=cot[2]=cot[3]=cot[4]=0;
    for(int i=-3;i<4;i++)
    for(int j=-(3-abs(i));j<=3-(abs(i));j++)
    {
        if(x+i>0&&x+i<=n&&y+j>0&&y+j<=n) cot[a[x+i][y+j]]++;
    }
    cot[a[x][y]]--;
    cot[4]=pro=a[x][y];
    cot[4]=0;
    while(cou!=9)
    {
        int temp=(8*cou*cou-cot[4]+pro-1)/pro;
        round+=temp;cot[4]+=temp*pro;cou++;
        if(cot[3]!=0)
        {
            cot[3]--;pro+=3;
        }else
        if(cot[2]!=0)
        {
            cot[2]--;pro+=2;
        }else
        if(cot[1]!=0)
        {
            cot[1]--;pro+=1;
        }
    }
    ans[x][y]=round;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        minans=1e9;
        scanf("%d%d%d",&n,&x,&y);
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
        {
            BfsAndCalc(i,j);
            if((abs(x-i)+abs(y-j)+1)/2+ans[i][j]<minans) minans=(abs(x-i)+abs(y-j)+1)/2+ans[i][j];
        }
        printf("%d\n",minans);
    }
    return 0;
}


你可能感兴趣的:(题解(按比赛))