2020年百度之星初赛第一场

Drink

Problem Description

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

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

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

Input

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

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

接下来 n 行,每行两个整数 x[i],y[i](1≤x[i],y[i]100)

Output

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

Sample Input

2
1 10
3 3
2 10
3 3
2 1

Sample Output

12
5

思路:

求出每次需要补充的瓶数,进一步求出这次最少补充卡路里数多少,用min求出最小值

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int main()
{
	ios::sync_with_stdio(false);//关闭同步 
   	cout.tie(NULL);
   	cin.tie(NULL);
    int t,n,m,x,y,mi=10086;
	cin>>t;
	while(t--){
		cin>>n>>m;
		while(n--)
		{
			cin>>x>>y;
			int k=m/x;//补充完水分需要多少水 
			if(m-x*k)k++;//如果 x没有整除,数量增加 
			y=k*y;//卡路里数量 
			mi=min(y,mi);
		}
		cout<<mi<<endl;
		mi=10086; //更新数量 
	}
    return 0;
}

GPA

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≤test≤401) 表示数据组数。
接下来 test 行,每行一个正整数 x 表示四门考试的总分 (0≤x≤400)

Output

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

Sample Input

2
0
400

Sample Output

0.0
17.2

思路:

因为是用分数段,所以直接算每个分数段加起来和n比较,然后如果这次比较比n小,就对比上一次的学分绩谁高,更新一下

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int a[]={0,60,62,65,67,70,75,80,85,90,95};//初始化分数段 
double b[305];
void init()//初始化分数段的学分绩 
{
	b[0]=0.0;
	b[60]=1.0;
	b[62]=1.7;
	b[65]=2.0;
	b[67]=2.3;
	b[70]=2.7;
	b[75]=3.0;
	b[80]=3.3;
	b[85]=3.7;
	b[90]=4.0;
	b[95]=4.3;
}
int main()
{
	init();
	ios::sync_with_stdio(false);//关闭同步 
   	cout.tie(NULL);
   	cin.tie(NULL);
   	int t;
   	cin>>t;
   	while(t--){
   		int n;
   		cin>>n;
   		double ans=0.0;
   	for(int i=0;i<=10;i++)
   	{
   		for(int j=0;j<=10;j++)
   		{
   			for(int k=0;k<=10;k++)
   			{
   				for(int o=0;o<=10;o++)
   				{
   					if(a[i]+a[j]+a[k]+a[o]<=n)
   					{
   						ans=max(ans,b[a[i]]+b[a[j]]+b[a[k]]+b[a[o]]);//四个循环,如果他们每个分数小于n,就把他们的学分绩算一遍,取最大值 
					   }
				   }
			   }
		   }
	   }
	   printf("%.1f\n",ans);
	   }
  
    return 0;
}

DEC

Problem Description

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

Input

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

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

Output

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

Sample Input

1
2 3

Sample Output

4

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

思路:

初始化dp,o1查询

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 7;
int dp[1005][1005];
inline int gcd(int x,int y) {//gcd函数 
    return y == 0 ? x : gcd(y,x % y);
}
int main()
{
   	dp[1][1]=1;
   	for(int i=1;i<=1000;i++)//dp初始化 
   	{
   		for(int j=1;j<=1000;j++)
   		{
   			if(dp[i][j])continue;
   			dp[i][j]=max(dp[i-1][j]+(gcd(i,j)==1?1:0),dp[i][j-1]+(gcd(i,j)==1?1:0));
		   }
	   }
   	
	int T;scanf("%d",&T);//o1询问 
    while(T--) {
        int a,b;scanf("%d%d",&a,&b);
        printf("%d\n",dp[a][b]);
    }
    return 0;
}

Civilization

Problem Description

这是一个回合制游戏,每一回合开始前会进行上一回合的结算。

有一张 n∗n 的棋盘,我们出生在一个初始位置 (x,y),现在我们要选择一个位置建设城市。

你的人物每回合可以移动到距离你曼哈顿距离不超过 2 的位置,移动完成后可以选择是否建立城市。

建立城市后,你的人物消失,成为一个人口为 1 的城市,这个人口要下回合才可以工作。如果不移动,直接在 (x,y) 建城,第 1 回合就可以开始工作。

对于城市的每个居民,你可以安排他到距离城市曼哈顿距离小于等于 3 的位置进行工作,此居民可以瞬间到达该位置,每个位置最多安排一个居民,失业的人口不会生产任何食物。

注意,城市位置上必须有一个居民在工作。

结算按照如下顺序:
1. 如果位置 (i,j) 上有一个工作居民,则获得 a[i][j] 的食物。
2. 如果当前城市人口为 i,且食物达到 8∗i2 时,你获得一个新的居民,下一回合可以进行操作。

当结算后城市总人口达到 9 游戏结束。

初始食物数量为 0,人口上涨不会导致之前积累的食物消失。输出最少几个回合能让游戏结束。
 

Input

第一行一个正整数 test(1≤test≤10) 表示数据组数。

对于每组数据,第一行三个正整数 n(2≤n≤500),x(1≤x≤n),y(1≤y≤n),分别表示棋盘大小和起始位置。

接下来 n 行,每行 n 个整数,第 i 行第 j 列的整数表示 a[i][j](1≤a[i][j]3)

Output

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

Sample Input

1
10 9 8
1 2 2 1 2 3 1 1 2 1
2 1 3 3 3 2 3 2 3 1
1 1 3 1 1 3 2 2 1 2
3 1 3 1 3 3 1 3 1 3
3 2 3 1 3 1 2 2 2 1
2 3 2 3 2 2 3 1 2 3
3 1 3 3 2 2 3 2 3 3
1 3 3 2 3 2 2 2 1 1
3 3 1 2 3 2 1 2 1 2
1 1 3 1 3 1 1 1 3 3


Sample Output

39

思路:

直接模拟

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map> 
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e3+7;
int a[maxn][maxn],d[maxn][maxn];
int n;
int getdis(pair<int,int>a,pair<int,int>b)//计算曼哈顿距离 
{
	return abs(a.first-b.first)+abs(a.second-b.second);
}
int get(int x,int y) { //建城市的位置
    int t1 = 0,t2 = 0,t3 = 0;
    for(int i = max(1,x - 3);i <= min(n,x + 3);i++) {
        for(int j = max(1,y - 3);j <= min(n,y + 3);j++) {
            if(i == x && j == y) continue;
            if(getdis({x,y},{i,j}) <= 3) {
                int num = a[i][j];
                if(num == 1) t1++;
                if(num == 2) t2++;
                if(num == 3) t3++;
            }
        }
    }
    int sum = a[x][y]; //每一回合可以得到的食物
    int sumall = 0; //已经获得的食物
    int ans = 0;
    int person = 1; //城市人数
    while(person < 9) { //当前回合
        int nex = 8 * person * person;
        int num = (nex - sumall) / sum; //要多少回合才能加人
        if((nex - sumall) % sum) num++;
        sumall += num * sum;
        ans += num;
        person++;
        if(t3) {
            sum += 3;
            t3--;
        } else if(t2) {
            sum += 2;
            t2--;
        } else if(t1) {
            sum += 1;
            t1--;
        }
    }
    return ans;
}
int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int x,y;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]);
            }
        }
        int ans = get(x,y);
        for(int i = 1;i <= n;i++) {
            for(int j = 1;j <= n;j++) {
                if(i == x && j == y) continue;
                int num = getdis({x,y},{i,j});
                if(num % 2) {
                    num = num / 2 + 1;
                } else num = num / 2;
                ans = min(ans,get(i,j) + num);
            }
        }
        
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗蛋儿l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值