2019 IMCPC 复现训练

更新一下,在过了17天后终于靠着(不懈地问遍身边所有的人)写完了——521快乐呀
在这里插入图片描述

问题A 能量不守恒定律

题目描述
这个世界上有两种能量,a能量和b能量。
小花作为一个魔法师,每天的工作就是根据现有的能量资源去产生新的能量资源。众所周知的是,由于能量不守恒定律,小花所拥有的能量会越来越多!
产生能量的规则是这样的:小花每一天只能释放两个魔法,第一个是元素克隆,可以将b能量克隆相同的数目,并转变为a能量。第二个是能量跃迁,会根据你现有的a能量和b能量的数目,产生a和b的最大公约数的b能量(不消耗原来的能量)。
小花会严格按照魔法守则里的规定,即每天先做元素克隆,再做能量跃迁。
请问第k天之后,小花拥有a,b能量的数目分别是多少。

输入
第一行一个整数T,代表T组数据。(T<=100)
接下来每行3个数,x,y,k。代表a能量最初有x,b能量最初有y,询问第k天。(1<=x,y,k<=40)

输出
对于每组数据,输出两个数,以空格隔开,代表第k天放完魔法以后,拥有的a,b能量数,占一行。

样例输入
1
12 11 3
样例输出
48 14

#include<iostream>
#include<string>
#include<iomanip>
#include<algorithm>
#include<map>
using namespace std;
int main()
{
    
    
	long long int n,a,b,k,newA,newB;//n组数据,ab能量数,询问第k天
	cin >> n;
	for (int i = 0; i < n; i++)
	{
    
    
		cin >> a >> b >> k;
		//第k天
		for (int i = 0; i < k; i++)
		{
    
    
			a = a + b;
			newA = a;
			newB = b;
			while (newA != newB)
			{
    
    
				if (newA > newB)
					newA -= newB;
				else
					newB -= newA;
			}
			b = b + newA;//此时的newA是公约数
		}
		cout << a<<' ' << b << endl;

	}

}

问题 B: 图书管理员

题目描述
自从Rabbit当上了图书馆的管理员,最让她头疼的便是把同学借过的书放回到指定位置。
假设图书馆的书架共有n层,从上到下分别为1~n层,其中第i层书架一共有 a i a_i ai本书。
每一层的书籍从左往右分别编号为 1 1 1~ a i a_i ai
同时,每一本书的封面上有一个总编号,总编号由1到 a 1 + a 2 + . . . + a n a_1+a_2+...+a_n a1+a2+...+an,编号顺序为第一层先编号,同一层中左侧的书籍先编号。
现在Rabbit手里有一堆书,她只知道它们的总编号,不堪重负的Rabbit想让你告诉她每一本书应该放在第几层第几号。
比如, n = 2 n=2 n=2 a 1 = 4 a_1=4 a1=4 a 2 = 6 a_2=6 a2=6,那么书籍总编号为1~10,如果有一本书总编号为8,那么它应该被放回到第2层第4号。

输入
输入数据第一行为T,表示数据组数。(1<=T<=10)
每组第一行为两个整数n,m,分别表示书架层数和需要被整理的书籍数量。(1<=n,m<=10^5)
接下来一行有n个整数 a i a_i ai,表示每层书架的书籍数量。( 1 < = a i < = 1 0 5 1<=a_i<=10^5 1<=ai<=105)
最后一行m个整数 b i b_i bi,表示第i本书的总编号。( 1 < = b i < = a 1 + a 2 + . . . + a n 1<=b_i<=a_1+a_2+...+a_n 1<=bi<=a1+a2+...+an)

输出
对于每组数据,输出m行,每行两个整数x,y,表示第i本书应该被放回到第x层第y号。

样例输入 复制
1
2 2
4 6
3 8
样例输出 复制
1 3
2 4

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<map>
#define MAX_LEN 1000005
using namespace std;
long long int allbook[MAX_LEN];
long long int book[MAX_LEN];
long long int sc, bc, bn, n,i,j,u,k,f;
int main()
{
    
    
	 cin >> n;
	for ( i = 0; i < n; i++)
	{
    
    
		memset(allbook, 0, sizeof(allbook));
		memset(book, 0, sizeof(book));
		 cin >> sc >> bc;//书层数和书本数
		for (j = 0; j < sc; j++)//输入总编号
		{
    
    
			cin >> bn;//每层书的数量
			if (j == 0)
			{
    
    
				allbook[j] = bn;
			}
		   else
			{
    
    
				allbook[j] = bn+allbook[j-1];
			}
		}
		for ( u = 0; u < bc; u++)
		{
    
    
			cin >> book[u];//输入书本总编号
		}
		for ( k = 0; k < bc; k++)
		{
    
    
			f = lower_bound(allbook, allbook + sc, book[k])-allbook;
			if (f != 0)
			{
    
    
				cout << f + 1 << ' ' << book[k] - allbook[f - 1] << endl;
			}
			else
			{
    
    
				cout << f + 1 << ' ' << book[k]<< endl;
			}
		}
	}
}

问题 C: 逃离迷宫

题目描述
Rabbit在晚上回家的时候因为天太黑看不清路,陷入了一个迷宫里,她只能无助地留在原地等待救援。
由于Rabbit有很多粉丝,他们知道后立马展开了营救。
粉丝每一分钟可以上下左右移动一个位置,但是不能走出迷宫。
R a b b i t Rabbit Rabbit想知道自己最快多久能被找到。

输入
输入数据第一行为T,表示数据组数。(1<=T<=100)
每组第一行为两个数n,m,表示迷宫的大小。(1<=n,m<=200)
接下来n行,每行m个字符。’.‘表示可以走的点,’#'表示不可以走的点,'R’表示Rabbit所在的位置,每个’F’表示Rabbit的粉丝的起始位置。

输出
对于每组数据,如果Rabbit能被安全找到,输出最小时间。
否则输出"Poor Rabbit."

样例输入 复制
1
3 4
#.R#
F#…

样例输出 复制
5

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int dx[4] = {
    
     -1,0,1,0 };
int dy[4] = {
    
     0,1,0,-1 };
char map[300][300];
bool flag[300][300];
int xc, yc,Rx,Ry,n;//地图大小
struct node
{
    
    
	int x, y, step;
};
bool canwalk(int x, int y)
{
    
    
	return x < 0 || x >= xc || y < 0 || y >= yc || flag[x][y] || map[x][y] == '#';
}
void search(int x, int y)
{
    
    
	node point;
	point.x = x;
	point.y = y;
	queue<node>que;
	point.step = 0;
	que.push(point);//把兔子坐标存入
	flag[x][y] = true;
	while (!que.empty())
	{
    
    
		node mynode = que.front();//第一个
		que.pop();//清除,然后存下一个
		if (map[mynode.x][mynode.y] == 'F')//找到
		{
    
    
			cout << mynode.step << endl;
			return;
		}
		for (int i = 0; i < 4; i++)//搜索
		{
    
    
			node newnode;//下一个点
			int xx = mynode.x + dx[i];
			int yy = mynode.y + dy[i];
			newnode.x = xx;
			newnode.y = yy;
			newnode.step = mynode.step + 1;
			if (!canwalk(xx, yy))//边界条件
			{
    
    
				flag[xx][yy] = true;
				que.push(newnode);//存入
			}
		}
		
	}
	cout << "Poor Rabbit." << endl;
}
int main()
{
    
    
	 cin >> n;
	for (int i = 0; i < n; i++)
	{
    
    
		cin >> xc >> yc;
		memset(flag, false, sizeof(flag));
		for (int j = 0; j < xc; j++)
		{
    
    
			for (int k = 0; k < yc; k++)
			{
    
    
				cin >> map[j][k];
				if (map[j][k] == 'R')
				{
    
    
					Rx = j;
					Ry = k;
				}
			}
		}
		search(Rx, Ry);
	}
}

问题 D: 勇士传说

题目描述
勇士 haruhi 要铸造一个传说!

但是在这之前,他需要打败恶龙。

众所周知的是,恶龙的攻击力非常高,haruhi 作为一个攻击力只有 0 的家伙,需要去招 募青蛙来攻打恶龙。

haruhi 到恶龙巢穴的路上有 n 个酒馆,每个酒馆里都有一些青蛙。(不要问青蛙为什么 在酒馆里)

青蛙作为一种中立生物,对 haruhi 也是有敌意的,除非 haruhi 花钱招募它们,或者 haruhi 已经招募的青蛙的攻击力比当前酒馆里青蛙的攻击力多或者相等,他才能安全地走出这个酒 馆,抵达下一个地方。

haruhi 会按照 1 到 n 的顺序,走遍这些酒馆。

现在,haruhi 想要问你,他最少需要准备多少钱,才能招募到足够多的青蛙,打败恶龙。

其他设定如下:

1、haruhi 只能够选择要么招募整个酒馆的青蛙,要么一只都不要。

2、最后,青蛙的攻击力总和大于等于恶龙,那么,haruhi 就可以顺利的打败恶龙。

3、同一个酒馆里,青蛙的攻击力是一样的。

输入
第一行一个整数 T,代表 T 组数据。(T<=20)

首先每行两个数 n,k,分别代表酒馆的数量,和恶龙的攻击力。(n<=500,k<=10^9) 接下来有三行。

第一行 n 个数,代表每个酒馆里青蛙的数量。(1<=a[i]<=3000)

第二行 n 个数,代表每个酒馆里每只青蛙的攻击力。(1<=b[i]<=3000)

第三行 n 个数,代表招募到这个酒馆所有青蛙所需要付出的金币数。(1<=c[i]<=10)

输出
对于每组数据,输出一个数,代表 haruhi 需要花的最少钱数。

如果 haruhi 战胜不了恶龙,输出"chu ti zhe ying gai xue yi xia e long"。(不含引号) Sample

样例输入 复制
1
3 9
2 2 3
3 4 1
5 8 1
样例输出 复制
13

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1010], b[1010], c[1010],dp[5020][5020],n,k,t;
int main()
{
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	 cin >> t;
	while (t--)
	{
    
    
	    cin >> n >> k;
		for (int i = 1; i <= n; i++)
		cin >> a[i];
		for (int i = 1; i <= n; i++)
		cin >> b[i];
	    for (int i = 1; i <= n; i++)
	    cin >> c[i];
		memset(dp, -1, sizeof(dp));
		dp[1][c[1]] = a[1] * b[1];//第一个
		for (int i=2; i <= n; i++)
		{
    
    
            for (int j = 1; j <5000; j++)
			{
    
    
				//j - c[i]>0代表当前的钱够买当前酒馆的青蛙
				/*dp[i - 1][j - c[i]] > -1表示上一个酒馆的攻击力大于-1,
				也就是说j是本酒馆的钱,不然相减等于-1,所以说到了j先给他赋值,然后再
				进行下一个if判断,下一个if可能判断可能不判断。这也就是那个一维不对的的地方。
				没有在下一个if不判断的时候强硬加上本酒馆买青蛙的金币*/
				if (j - c[i] > 0 && dp[i - 1][j - c[i]] > -1)
				{
    
    
					dp[i][j] = dp[i - 1][j - c[i]] + a[i] * b[i];//加上
				}
			 /* dp[i][j] = max(dp[i - 1][j], dp[i][j]);代表上一个酒馆在上一个酒馆用一样的钱,
			 买到的攻击力大于此时酒馆青蛙的攻击力,找到此时钱能在这个酒馆买到的最大额度,
			 但这条件是dp[i - 1][j] >= a[i] * b[i],这说明在上一个酒馆买到的青蛙已经比此时大了
			 不然只能被花钱,不能有选择的余地
			 */
			   if (dp[i - 1][j] >= a[i] * b[i])
			   {
    
    
				   dp[i][j] = max(dp[i - 1][j], dp[i][j]);
			    }
		     }
		}
		int flag = -1;
		for (int u = 1; u <5000; u++)
		{
    
    
			if (dp[n][u] >= k) {
    
    
				flag = false;
				cout << u << endl;
				break;
			}
		}
		if (flag == -1)
		{
    
    
			cout << "chu ti zhe ying gai xue yi xia e long" << endl;
		
		}
	}

}

问题 E: 树上分支

题目描述
有的时候,题目和内容是没有一点关系的。

当然,作为一个有责任心的出题者,会把题目和名字紧紧联系在一起。

显然,小花不是一个有责任心的出题者。

由于他想尽早的完成出题任务,于是他把出题的流程抽象成了一棵树。

例如,当出完题目后,小花可以选择先写标程,或是先造数据。但找人验题, 一定是在造完数据以后。

他现在正处在其中的某个阶段,你可以把所有的阶段都视为一个点。

烦人的 boss 又在催促他,并询问最快还有多久才能到第 x 个阶段。 所有的询问相互独立。

输入
第一行一个整数 T,代表 T 组数据。(T<=500)

接下来每行三个数 n,m,r。代表有 n 个阶段,m 个询问,小花现在正处在 第 r 个阶段。(1<=n,m<=100000)

接下来 n-1 行,每行两个数,u,v,代表 v 阶段在 u 阶段之后。(1<=u,v<=n)

接下来一行有 m 个数,代表 boss 询问到第 x 个阶段还有多久。(1<=x<=n)

输出
对于每组数据,输出 m 个数,代表小花最快还有几步才能到要求的阶段。

如果小花已经完成了 boss 询问的那个阶段,那么对此询问输出 0。

如果无法确定小花是不是完成了那个阶段,输出-1。

如果询问的就是小花所在的阶段,输出 0。

每个询问后输出一个空格,每组数据后输出一个换行。

样例输入 复制
1
5 2 1
1 2
1 3
2 4
2 5
3 4
样例输出 复制
1 2

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
int X,n,m,r,u,v;
vector<int>m1[1000005], m2[1000005];
bool didsearch[100005];
int ans[100005];
int main()
{
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> X;
	while (X--)
	{
    
    
		cin >> n >> m >> r;
		memset(didsearch, false, sizeof(didsearch));
		memset(ans, -1, sizeof(ans));
			for (int i = 1; i <=n; i++)
			{
    
    
				m1[i].clear();
				m2[i].clear();
			}
			for (int j = 2; j <= n; j++)
			{
    
    
				cin >> u >> v;
				m1[u].push_back(v);
				m2[v].push_back(u);
			}
			queue<int>que;
			que.push(r);
			didsearch[r] = true;
			ans[r] = 0;
			while (!que.empty())
			{
    
    
				int f = que.front();
				for (auto j:m1[f])//相当于把j赋值为m1[f],auto是为了迭代器定义的方便
				{
    
    
					if (didsearch[j] == false)
					{
    
    
						que.push(j);
						didsearch[j] = true;
						ans[j] = ans[f] + 1;
						
					}
				}
				que.pop();
			}
			//反向搜索,已经做过的变成0
			//因为m1,m2输入的时候是从2开始,如果那么所在阶段的点就为false,因为反向遍历,就可以把干过的点置为0
			que.push(r);
			while (!que.empty())
			{
    
    

				int f = que.front();
				for (auto j:m2[f])
				{
    
    

					if (didsearch[j] == false)
					{
    
    
						que.push(j);
						didsearch[j] = true;
						ans[j] =0;
					}
				}
				que.pop();
			}
			int a;
			while (m--)
			{
    
    
				cin >> a;
				cout << ans[a] << ' ';
			}
			cout << endl;
	}
}

问题 F: 花园小学运动会

题目描述
花园小学正在进行紧张刺激的运动会!每个班级都有一个独一无二的数字。 现在正是 10000 米短跑比赛的现场。许多班级的运动员们已经纷纷准备就绪。正 等一声令下,开始比赛。10000 米短跑比赛有一个传统,就是每当一个运动员跑 到终点时,都会大声喊出他的班级号,来显示一种荣耀。现在,给出 n 个数,代 表通过终点的 n 个人所喊出的班级号,你需要统计有多少班级在这场比赛中参赛 了正好 k 个人,计算出在这些班级中,获得第一名的选手是哪个班级的。输出他 所在的班级号。

假设每一个参加比赛的人都通过了终点。

输入
每组数据第一行, n, k。

代表有 n 个人,要求保留 k 个人的班。 (n,k<=1000000) 接下来一行 n 个数,依次代表选手通过终点所喊出的班级号(a[1]代表第一 个通过终点的选手喊出的班级号,依次类推)。

(a[i]<=1000000) 处理到文件结束。

输出
每行一个数。

若没有班级通过 k 人,输出-1。

样例输入 复制
5 2
4 2 3 2 3
样例输出 复制
2

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<map>
#define MAX_LEN 1000005
using namespace std;
int Personalrank[MAX_LEN] , classRank[MAX_LEN];
int main() {
    
    
	long long int k,n,x,i,j,flag=1;//共用有n人参赛,标准k
	while (cin >> n >> k)
	{
    
    
		flag = 1;
		memset(classRank, 0, sizeof(classRank));
		for (i = 1; i <= n; i++)
		{
    
    
			cin >> x;
			Personalrank[i] = x;//记录第几名是哪个班级
			classRank[x]++;//记录班级过线人数
		}
		for (j = 1; j <= n; j++)//遍历名次
		{
    
    
			if (classRank[Personalrank[j]] == k)
			{
    
    
				cout << Personalrank[j] << endl;
				flag = 0;
				break;
			}
		}
		if (flag == 1)
		{
    
    
			cout << "-1" << endl;
		}
	}
}

问题 G: Rabbit 的考研之路

题目描述
大三的 Rabbit 已经开始考研了,她需要参加数学、英语、政治、专业课四门

考试,四门课的满分分别是 150,100,100,150。

不过她了解到考研与普通考试不同,要想被录取不仅要总分到达国家线(320 分),而且单科成绩也必须到达单科线。 这里每门课的单科线为这门课满分的 60%。

过了几个月,考研成绩出来了,Rabbit 得到了班上所有 N 位同学的成绩,现 在她想知道哪些同学能被录取,并根据她们的总分从大到小排序(若总分相同, 则按照名字的字典序从小到大排序)。

注:到达指的是大于等于,数据保证学生名字是只由小写字母和大写字母组 成的不同字符串,且至少有一位同学能被录取。

输入
输入数据第一行为 T,表示数据组数。(1<=T<=20)

每组数据第一行为 N,表示学生人数。(1<=N<=100)

接下来 N 行,每行首先是一个字符串 S,表示第 i 个学生的名字,接下来四个 整数 M,E,P,Z,分别表示该学生的数学成绩,英语成绩,政治成绩,专业课成绩。 (1<=|S|<=10,1<=E,P<=100,1<=M,Z<=150)

输出
对于每组数据输出若干行,每行输出被录取的学生按照成绩排序后的名字和 总分,用空格隔开。
样例输入 复制
1
3
Bob 105 70 65 110
John 135 55 70 120
Tom 100 75 70 120
样例输出 复制
Tom 365
Bob 350

#include<iostream>
#include<cstring>
#include<string>
#include<iomanip>
#include<algorithm>
#define MAX_LEN 1000005
using namespace std;
struct people
{
    
    
	string name;
   int allgrade;
}item[MAX_LEN];

bool com(people a,people b)
{
    
    
	if (a.allgrade == b.allgrade)
	{
    
    
		return a.name < b.name;
	}
	
		return a.allgrade > b.allgrade;
	
	
}
int main()
{
    
    
	long long int n, x,i,j,ac=0;
	int f, g, h, k,all;
	string d;
	cin >> n;//多少组数据
	for (i = 0; i < n; i++)
	{
    
    
		//memset(item, 0, sizeof(item));
		ac = 0;
		cin >> x;//多少人
		for (j = 0; j < x; j++)
		{
    
    
			cin >>d>> f >> g >> h >> k;
			all = 0;
			all = f + g + h + k;
			
			if (f >= 90 && g >= 60 && h >= 60 && k >= 90&&all>=320)
			{
    
    
				item[ac].name = d;
				item[ac].allgrade = all;
				ac++;
			}
			
		}
		sort(item, item + ac, com);
		for (j = 0; j < ac; j++)
		{
    
    
			
				cout<<item[j].name<<' '<< item[j].allgrade <<endl;
		
		
		}

	}
}

问题 H: Rabbit 的秘密纸条

题目描述
Rabbit 得到了一张秘密纸条,上面是由密密麻麻的小写字母组成的字符串。
已知,字符 c 与字符’z’-c+'a’是相反的。(即‘a’与‘z’,‘ b’与‘y’…)

现在规定对称相反子串的定义为该子串从中间到两边对应位置的字符都是 相反的。

例如给定字符串"azza",其对称相反子串有“a”,“z”,“az”,“azz”,“zza”,“za”。

Rabbit 想知道最长的对称相反子串的长度是多少?

输入
输入数据第一行为 T,表示数据组数。(1<=T<=10)

每组数据占一行,为字符串 S。(1<=|S|<=1000)

输出
对于每组数据输出一个整数,代表最长的对称相反子串的长度,占一行。
样例输入 复制
2
kadwxdwz
abcdevdcba
样例输出 复制
7
2

#include<iostream>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
bool ismatch(char x,char y)
{
    
    
	if (x== 'z' - y + 'a')
	{
    
    
		return true;
	}
	return false;
}
int howlength(int i, int j, string s)
{
    
    
	int sum = 0;
	while (i >= 0 && j < s.length())
	{
    
    
		if (ismatch(s[i], s[j]))//判断是否对称
		{
    
    
			sum += 2;
		}
		else {
    
    
			break;
		}

		i--; j++;//往两边搜索
		
	}
	return sum;
}
int main()
{
    
    
	 int n; cin >> n;
	for (int p = 0;p < n; p++)
	{
    
    
		string s;
		cin >> s; int maxx = 0;
		for (int i = 0; i < s.length(); i++)
		{
    
    
			maxx = max(howlength(i - 1, i + 1, s) + 1, maxx);//此处判断例如aabzz这种奇数情况
			maxx = max(howlength(i, i + 1, s), maxx);//aazz这种情况

		}
		cout << maxx << endl;
	}
}

问题 I: Rabbit 的郊游之旅

题目描述
Rabbit 考研结束后相约与同学去郊游。

他们想尽快到达目的地,但是有的人 走得快有的人走得慢,这让 Rabbit 很苦恼。

不过好在 Rabbit 能够对走得比较慢的人施展魔法。

假设第 i 个人的步行速度为 vi 米/分钟,对他施展魔法之后能让他的速度变为 wi 米/分钟。

现在 Rabbit 想知道他们最快能在第几分钟全部达到目的地。

注:一分钟只能施展一次魔法,且持续时间为一分钟。

输入
输入数据第一行为 T,表示数据组数。(1<=T<=10)

每组数据第一行为两个整数 N, S,分别表示学生总数和距离目的地的距离。 (1<=N,S<=10^5)

接下来 N 行,第 i 行有两个整数 vi,wi。(1<=vi<=wi<=10^5)

输出
对于每组数据输出一个整数,表示最快能在第几分钟全部达到目的地,占一 行。
样例输入 复制
1
3 9
5 10
2 4
3 7
样例输出 复制
3

题解:这道题主要还是利用二分查找,但是怎么判断时间是否可以则不太好想,我的想法是:循环每个人的时间与被判断的时间相比较,若大于则需要加速,算完以后把总时间与判断时间相比较,大于则不行。例如输入数据之内的3,之所以不是1.8的原因是4.5秒的同学就算加速后也不能在1.8秒之内到达,所以1.8是不行的。那么还有一个问题,为什么答案一定是某个同学原速度的其中一个速度呢,理解上面一个问题以后就能很好想通这一点。因为一次只能加速一个人,比他时间小的同学不需要加速只有比他大的同学才需要,所以是已他自己作为评判依据的。

#include<iostream>
#include<algorithm>
#include<stdio.h>
#define MAX_LEN 1000005
using namespace std;
int n, s,v[MAX_LEN],w[MAX_LEN],a,b,timee[MAX_LEN];
int maxtime;
bool iscango(int a)
{
    
    
	int flag = 1;
	int time2 = a;
	int t3 = 0;//计算后时间
	for (int i = 0; i < n; i++)
	{
    
    
		if (timee[i] <= a) 
			continue;
		int s1 = v[i] * a;//在判断时间内可以走多少
		int s2 = s - s1;
		int vv= w[i] - v[i];//速度差
		if (vv == 0) return 0;
		if (s2 % vv) t3 = t3 + 1 + s2 / vv;
		else t3 = t3 + s2/ vv;
		if (t3 > a)
		{
    
    
			flag = 0; 
			break;
		}
	}

	return flag;
}
int main()
{
    
    
	int t;
	scanf("%d", &t);
	while (t--) {
    
    
		scanf("%d%d", &n, &s);
		maxtime = 0;
		for(int i=0;i<n;i++)
		{
    
    
			int a, b;
			scanf("%d%d", &a, &b);
			v[i] = a; w[i] = b;//存入每个学生的原速度和加速后速度
			int x = s % a;
			int t1 = s / a;//求速度
			if (x) timee[i] = t1 + 1;
			else timee[i] = t1;
			maxtime = max(timee[i], maxtime);
				
		}
		int star = 1,end = maxtime;
		int minn= maxtime;
		int mid;
		while (star < end)//二分
		{
    
    
			mid = (star + end) /2;
			if (iscango(mid))
			{
    
    
				end = mid;
				minn= min(minn, mid);
			}
			else star= mid + 1;
		}
		cout << minn << endl;
	}
	
}

问题 J: 寻找敌军

题目描述
小明在玩一个战略游戏。他现在的任务是找到敌方的军队在什么地方。他已 经知道敌方的军队可能在的几个区域和每个区域敌方的军队可能存在的概率,且 敌方的军队只可能存在于这些区域中的某一个区域当中。他拥有一个科技:可以 同时扫描若干个区域并花费区域个数的金钱。但游戏有一定的限制,小明必须将 这些区域分成 k 组,且只能对 k 组的区域依次进行一次扫描。现在小明想知道怎 么样的划分区域的策略可以使得找到敌军时花费的金钱数的数学期望最小。
输入
输入第一行是一个正整数 T(T<=10),表示数据组数。

接下来对于每组数据 , 第一行给出两个正整数n(1<=n<=100) 和 k(1<=k<=n<=100),分别表示区域个数和划分组数。第二行给出 n 个不超过 100 的正整数,依次代表每个区域的概率(单位:%), 其中保证所有区域的概率相 加等于 100%。

输出
对于每组数据,输出一个实数,表示花费金钱数的数学期望的最小值,保留 3 位小数。
样例输入 复制
2
5 2
30 5 10 30 25
5 5
30 5 10 30 25
样例输出 复制
3.200
2.300

问题 K: 小明的比赛

题目描述
小明的算法竞赛水平很高,他经常参加网上的比赛。

比赛的规则是这样的:要在规定时间内解决 n 道题,解决时间越晚失去的 分数就越多。

当然如果有错误提交还会扣额外的分数。为了简化题目,我们假设小明所有 题目都可以一遍 AC。

小明实在是太强了,以致于他看完所有题目就都会做了。

剩下的就是把它们 写出来的问题。

小明掐指一算,算出了写每道题需要的时间 Ti,以及每道题每分 钟会失去的分数 Ai。

也就是说,如果他在 x 分钟时完成这道题,他将失去 x * Ai 的分数。 请合理安排做题顺序,使得当小明做完比赛时,失去的分数尽可能少。

输入
第一行给出一个正整数 T(T<=10),表示数据组数。

对于每组数据,第一行一个正整数 n,表示这场比赛的题目数。第二行 n 个 整数,表示做每道题需要的时间 Ti。

第三行 n 个整数,表示每题每分钟失去的分 数 Ai。 其中:0<n<=100000,0<Ti,Ai<=10000

输出
对于每组数据,输出一个整数,表示最少失去的分数。
样例输入 复制
1
3
10 10 20
1 2 3
样例输出 复制
150

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
#define MAX_LEN 1000005
using namespace std;
struct complex
{
    
    
	int time; int mark;double proportion;
};
complex  item[MAX_LEN];
bool com(complex a,complex b)
{
    
    
	return a.proportion > b.proportion;
}
int main()
{
    
    
	long long int x,n,i,j,sum=0,alltime=0;//x组数,n题目数
	cin >> x;
	for (i = 0; i < x; i++)
	{
    
    
		memset(item, 0, sizeof(item));
		sum = 0,alltime=0;
		cin >> n;
		for (j = 0; j < n; j++)
		{
    
    
			cin >> item[j].time;
		}
		for (j = 0; j < n; j++)
		{
    
    
			cin >> item[j].mark;
		}
		for (j = 0; j < n; j++)
		{
    
    
			item[j].proportion = (double)item[j].mark / (double)item[j].time;
		}
		sort(item, item + n, com);
		for (j = 0; j < n; j++)
		{
    
    
			alltime += item[j].time;
			sum += alltime * item[j].mark;
		}
		cout << sum << endl;
	}
	return 0;
}

问题 L: 礼物

题目描述
小明来到礼品店准备给女朋友挑选礼物。店员给小明展示了 n 个商品,这 n 个物品排成一排。并表示如果小明购买连续的 c 个商品会有特别大的优惠。小明 接受了店员的提议,决定购买连续的 c 个商品。这 n 个商品每个都有一个美观度 ai。小明不希望自己送的礼品美观度都太低,所以希望买到的 c 个商品的美观度 都能比 k 大。小明想知道有多少种购买方案能够达到这个要求。
输入
第一行给出一个正整数 T(T<=10),表示数据组数。

对于每组数据,第一行给出三个整数 n(1<=n<=200000),k(0<=k<=1e9)和 c(1<=c<=n)。第二行给出 n 个正整数 ai(0<=ai<=1e9),依次表示 n 个商品的美观 度。

输出
对于每组数据,输出一个整数表示能够达到要求的购买方案数,占一行。
样例输入 复制
3
4 3 3
2 3 1 1
1 1 1
2
4 0 3
2 3 1 1
样例输出 复制
0
1
2

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<map>
#define MAX_LEN 1000005
using namespace std;
int items[MAX_LEN];
int main() {
    
    
	long long int x,n,i,j,k,c,b,count=0,ans=0;
	cin >> x;
	for (i = 0; i < x; i++)
	{
    
    
		count = 0, ans = 0;
		cin >> n >> k >> c;//n个商品,k美观度,连续c个
		memset(items, 0, sizeof(items));
		for (j = 0; j< n; j++)
		{
    
    
			cin >> b;
			items[j] = b;
		}
		for (j = 0; j < n; j++)
		{
    
    
			if (items[j] > k)
			{
    
    
				count++;
				if (count >= c)
				{
    
    
					ans++;//因为是连续,所以多一个就多一种方法,不需要再次遍历
				}
			}
			else//遇到不满的K的,之前的计数清零
			{
    
    
				count = 0;
			}
		}
		cout << ans << endl;
	}
}

问题 M: 赌徒的必胜策略

题目描述
下面是传说中的赌徒必胜策略:

如果输的话按上把下注额翻倍下注,这样即使连败,因为总有获胜的时候, 只要赢一次就可以把输的钱全部赢回,当钱不足以按策略下注时,就把拥有的所 有钱都下注。

现在两个赌狗 A,B 都学到了这个方法,他们决定带着钱找对方练一练,他 们每次都进行一次胜率各为 50%的赌局,赌局的大小由上局输的人决定(第一次 赌局的大小为 1 元),一直到其中一个人的钱输光为止。

请你告诉这两个赌狗, 他们赢光对方钱的概率为多少。

输入
第一行一个正整数 T,表示共有 T(T<=100)组数据

接下来每一行两个正整数 a,b(1<=a,b<=100),分别表示 A 和 B 拥有的钱

输出
输出一个实数,表示 A 获胜的概率,保留三位小数。
样例输入 复制
1
1 1
样例输出 复制
0.500

#include<iostream>
#include<cstring>
#include<string>
#include<iomanip>
#include<algorithm>
#define MAX_LEN 1000005
using namespace std;

int main()
{
    
    
	double a, b,c;
	int n; cin >> n;
	for (int i = 0; i < n; i++)
	{
    
    
		cin >> a >> b; c = a + b;
		cout << fixed << setprecision(3) << a / c << endl;
	}
}

问题 N: 点

目描述
平面上有 n 个点(任意两点的横坐标与纵坐标都不会相同),每个点向 x 轴 和 y 轴做垂线分别形成两个交点,两个交点和该点以及坐标原点构成一个矩形, 并覆盖矩形内的点(在边缘上的点不算被覆盖),请输出平面上所有一次也没有 被覆盖过的点。
输入
第一行一个正整数 T(T<=5),表示共有 T 组数据。

每组数据的第一行一个正整数数 n(1<=n<= 200000),表示平面上有 n 个点。

接下来 n 行每行两个正整数 x,y(1<=x,y<= 1e9)表示一个点的横纵坐标。

输出
按 x 轴坐标从小到大输出所有符合条件的点。
样例输入 复制
1
5
8 1
17 5
9 6
12 11
13 7
样例输出 复制
12 11
13 7

#include<iostream>
#include<cstring>
#include<string>
#include <cstdio>
#include<iomanip>
#include<algorithm>
#define MAX_LEN 1000005
using namespace std;
struct point
{
    
    
	int x, y, flag;
}pointitem[MAX_LEN];
int com(point a, point b)
{
    
    
	return a.x <b.x;
}
int main()
{
    
    
	int  n;
	cin >> n;
	for ( int i = 0; i < n; i++)
	{
    
    
		memset(pointitem, 0, sizeof(pointitem));
		int x ;
		cin >> x;
		for (int j = 0; j < x; j++)
		{
    
    
			cin >> pointitem[j].x >> pointitem[j].y;
			pointitem[j].flag = 0;//先默认未填充
		}
		sort(pointitem, pointitem + x, com);
		int minn = 1e9 + 5, maxx = 0;//初始化变量
		for (int j = x-1; j >=0; j--)
		{
    
    
			if (pointitem[j].x<=minn && pointitem[j].y<=maxx)//虽然已经排好顺序,但是为了初始化边界添加minn的if语句,也可以手动加
			{
    
    
				pointitem[j].flag = 1;//表示被覆盖
			}
			minn = min(minn, pointitem[j].x);//更新边界
			maxx = max(maxx, pointitem[j].y);//y

		}
		for (int i = 0; i <x ; i++)
		{
    
    
			if (pointitem[i].flag == 0)
			{
    
    
				cout << pointitem[i].x << ' ' << pointitem[i].y<<endl;
			}
		}

	}
	return 0;
}

问题 O: 自闭

题目描述
世界上的大佬太多了,菜鸡们纷纷自闭并来到心理诊所寻求治疗,心理诊所 的每一个医生有不同的开始上班时间,能力 a 和收费 c,能力为 a 的医生可以治 好自闭程度小于或等于 a 的菜鸡。菜鸡们都很穷,所以他们只想要能治好他们 的最便宜的医生,请你告诉他们当前能治好他们病的最便宜的医生的价格。(假 设治疗在瞬间完成,同一个医生可以连续接待任意个客人)

输入
第一行一个正整数 T(T<=5),表示数据的组数

每组数据第一行一个正整数 n(n <= 10^5),表示接下来有 n 行。

接下来 n 行中,若第一个数为 0,则接下来两个正整数 a,c 表示有一个能力 为 a,收费为 c 的医生上班了。若第一个数为 1,则接下来有一个正整数 b,表 示有一个自闭程度为 b 的菜鸡来寻求治疗(1<=a,b,c <= 10^9)。

输出
对每个寻求治疗的菜鸡,输出一个整数表示治疗需要的花费,如果没有医生 能治好他,输出“-1”。
样例输入 复制
1
8
1 19
0 17 5
0 1 6
1 12
1 15
0 5 7
0 3 9
1 3
样例输出 复制
-1
5
5
5

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<map>
#include <stdio.h>
using namespace std;
#define MAX_LEN 1000000005
double people[100005], money[100005];
int main()
{
    
    
    int T, p, n, k, i;
    double N, F, Max, Min, Minn, b;
    scanf("%d", &T);
    while (T--)
    {
    
    
        scanf("%d", &n);
        memset(people, 0, sizeof(people));
        memset(money, 0, sizeof(money));
        Max = 0;
        Min = MAX_LEN;
        k = 2;
        while (n--)
        {
    
    
            scanf("%d", &p);
            if (p == 0)
            {
    
    
                scanf("%lf%lf", &N, &F);
                if (N >= Max && F <= Min)
                {
    
    
                    Max = N;
                    Min = F;
                    people[1] = Max;
                    money[1] = Min;
                }
                else if (N<Max && F>Min)
                    continue;
                else
                {
    
    
                    people[k] = N;
                    money[k] = F;
                    k++;
                }
            }
            else
            {
    
    
                Minn = MAX_LEN;
                scanf("%lf", &b);
                for (i = 1; i < k; i++)
                {
    
    
                    if (b <= people[i])
                        if (Minn > money[i])
                            Minn = money[i];
                }
                if (Minn == MAX_LEN)
                    printf("-1\n");
                else
                    printf("%.0lf\n", Minn);
            }
        }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/AAliuxiaolei/article/details/106007784