第一次双周赛+图

第一次双周赛 + 图

7-1 Lily

题目描述

百合花(Lily)是一种美丽的花。她通常一年只开一次花,所以如果你看到百合花盛开,它会非常珍贵。然而,她对猫有剧毒,所以你必须注意让好奇的猫远离可爱的百合花。

你有n个网格的土壤土地排成一行,从1到n,其中一些是百合花。我们不想伤害百合,也不想伤害猫。你可以在网格上放一些猫粮,但对于任何有猫粮的网格i,在区域[i−1,i+1]不得含有百合花。你喜欢猫和百合,所以你想最大限度地增加有猫粮的格子。

设计满足上述要求的计划。

输入格式

有一个整数n(1≤n≤1000)表示网格的数量。

第二行包含仅由“L”和“.”组成的字符串R,表示有和没有百合花的格子。

输出格式

输出包含一行,字符串R′仅由“L”、“”组成和“C”,其中“C”表示在满足上述要求的同时分配给R中空网格的猫粮。

输入样例

5
..L..

输出样例

C.L.C

代码

#include<iostream>
#include<string>
using namespace std;



int main() {
	string s;
	int n;
	cin >> n >> s;
	bool stay = false;  //不改变当前字符
	for (int i = 0; i < n; ++i) {
		if (s[i] == '.' && !stay) {
			s[i] = 'C';
		}
		else if(s[i] == 'L') {
			stay = true;
			if (i > 0 && s[i - 1] != 'L') {
				s[i - 1] = '.';
			}
		}
		else if (stay) {
			stay = false;
			continue;
		}
	}
	cout << s;
	return 0;

}

7-2 a * b

题目描述

给出两个不超过1000位的十六进制数a,b。
求a∗b的值

输入格式

输入共两行,两个十六进制的数

输出格式

输出一行,表示a∗b

输入样例

1BF52
1D4B42

输出样例

332FCA5924

代码

#include<iostream>
#include<string.h>
#include<string>

using namespace std;

char a[1010];
char b[1010];

char c[1010];  //反存a
char d[1010];  //反存b
char ans[1000010];


int getNum(char ch) {
	if (ch >= 'A') {
		return ch - 'A' + 10;
	}
	else
		return ch - '0';
}

int main() {
	cin.getline(a, 1010);
	cin.getline(b, 1010);
	int lenA = strlen(a);
	int lenB = strlen(b);
	for (int i = 0; i < lenA; ++i)
		c[i] = a[lenA - 1 - i];
	for (int i = 0; i < lenB; ++i)
		d[i] = b[lenB - 1 - i];
	for (int i = 0; i < 1000010; ++i)
		ans[i] = '0';
	
	/*for (int i = 0; i < lenA; ++i)
		cout << c[i];
	cout << endl;
	for (int i = 0; i < lenB; ++i)
	cout << d[i];*/

	int cou = 0;

	for (int i = 0; i < lenA; ++i) {
		int up = 0;
		for (int j = 0; j < lenB; ++j) {
			//将c当前的字符转换为数字
			 int m1 = getNum(c[i]);
			//将d当前的字符转换为数字
			 int m2 = getNum(d[j]);
			 //将ans当前的字符转换为数字
			 int ma = getNum(ans[i + j]);
			 
			int m = m1 * m2 + up + ma;
			//cout << "m1 = " << m1 << " m2 = " << m2 <<" ma = " << ma << " m = " << m << endl;
			up = m/ 16;
			int k = m % 16;
			//cout << "up = " << up << " k= " << k << endl;
			/*cout << m << endl;*/
			if (k >= 10)
				ans[i + j] = 'A' + k - 10;
			else
				ans[i + j] = '0' + k;
			//cout << "ans[i + j] = " << ans[i + j] << endl;
		}
		if (up && up < 10)
			ans[i + lenB] = '0' + up;
		else if(up >= 10 && up < 16)
			ans[i + lenB] = 'A' + up - 10;
	}

	/*int i = 0;
	while (ans[i] != '0')
		cout << ans[i++];*/

	int start = 1000009;
	while (ans[start] == '0') {
		start--;
	}

	for (int i = start; i >= 0; --i)
		cout << ans[i];
	
	return 0;
}

注意点

  • 乘法运算的时候要从后往前乘法
  • 十六进制有A,B,C,D,E,F,在运算到对应数字时要更换

7-3 山头狙击战

题目描述

小明为了掩护大部队,单枪匹马同敌人周旋,后来被敌人包围在某山头……等等,为什么怎么听怎么像狼牙山五壮士!不过不用着急,这次小明携带了足够的弹药,完全可以将涌上来的敌人一个一个干掉。小明是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑和面子问题,小明会等待敌人靠近然后射击。
正当小明为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花k秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时小明无法将他击毙,那么我们可怜的小明就将牺牲在敌人的刺刀下。现在小明用心灵感应向你发出求助:要保住自己的性命并且歼灭所有敌人,小明最多只能用多少时间给枪装上一发子弹?
说明:假设一开始小明的枪中就有一发子弹,并且一旦确定一个装弹时间,小明始终会用这个时间完成子弹的装卸。希望你能帮助小明脱离险境。

输入格式

每组输入数据,第一行有两个整数n和m,(2≤n≤100,000; 1≤m≤10,000,000)n代表敌人个数,m代表小明的射程。
接下来有n行,每行一个整数mi,(1≤mi≤10,000,000),代表每个敌人一开始相对山头的距离(单位为米)。

输出格式

每组输出数据仅有一个整数,代表小明的换弹时间(单位为秒)。

输入样例

6 100
236
120
120
120
120
120

输出样例

25

代码

#include<iostream>
#include<algorithm>
using namespace std;

int enemy[10000000];
int n, m;

bool check(int k) {
	int time = 0;  //相当于总度过的时间
	if (enemy[0] > m)  //第一个敌人在射程之外
		time += enemy[0] - m;
	for (int i = 1; i < n; ++i) {
		time += k;  //换弹的固定时间
		if (time > enemy[i])  //需要的时间已经超过了敌人到眼前的时间
			return false;
		if (enemy[i] - time > m)  //敌人在射程之外,直接加上敌人到最大射程的时间
			time = enemy[i] - m;  
	}
	return true;
}

int main() {
	cin >> n >> m;
	for (int i = 0; i <= n; ++i)
		cin >> enemy[i];
	sort(enemy, enemy + n);
	int left = 0, right = m;
	int mid;
	while (left <= right) {
		mid = left + (right - left) / 2;
		if (check(mid))
			left = mid + 1;
		else
			right = mid - 1;
	}
	if (check(left))
		cout << left;
	else
		cout << right;
	return 0;
}

注意点

  • 二分答案,关键点是check函数
bool check(int k) {
	int time = 0;  //相当于总度过的时间
	if (enemy[0] > m)  //第一个敌人在射程之外
		time += enemy[0] - m;
	for (int i = 1; i < n; ++i) {
		time += k;  //换弹的固定时间
		if (time > enemy[i])  //需要的时间已经超过了敌人到眼前的时间
			return false;
		if (enemy[i] - time > m)  //敌人在射程之外,直接加上敌人到最大射程的时间
			time = enemy[i] - m;  
	}
	return true;
}

7-4 Reversing Linked List

题目描述

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.

输入格式

Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤10
5
) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

Then N lines follow, each describes a node in the format:

Address Data Next

where Address is the position of the node, Data is an integer, and Next is the position of the next node.

输出格式

For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

输入样例

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

输出样例

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

代码

#include<iostream>
#include<string>
#include<stack>
using namespace std;

typedef struct node {
	string address;
	int data;
	string next;
}node;

node str[100000];

void init() {
	for (int i = 0; i < 100000; ++i) {
		str[i].address = i;
		str[i].data = 0;
		str[i].next = -1;
	}
}

int StringToNum(string s) {
	if (s == "-1")
		return -1;
	int ans = (s[0] - '0') * 10000 + (s[1] - '0') * 1000 + (s[2] - '0') * 100 + (s[3] - '0') * 10 + (s[4] - '0');
	return ans;
}

void Traverse(string start) {
	int cur = StringToNum(start);
	while (true) {
		cout << str[cur].address << " " << str[cur].data << " " << str[cur].next << endl;
		cur = StringToNum(str[cur].next);
		if (cur == -1)
			break;
	}
	return;

}

void SeqTraverse(string start, int seq) {
	stack<node> temp;
	int cur = StringToNum(start);
	int num = 0, reverStart;
	string preAddress = "0";
	while (num < seq) {
		int next = StringToNum(str[cur].next);
		str[cur].next = preAddress;
		preAddress = str[cur].address;
		if (num == seq - 1)
			reverStart = StringToNum(str[cur].address);
		cur = next;
		num++;
	}
	//cout <<"Test: "<< str[cur].address << " " << str[cur].data << " " << str[cur].next << endl;
	str[StringToNum(start)].next = str[cur].address;
	/*while (!temp.empty()) {
		cout << temp.top().address << " " << temp.top().data << " " << temp.top().next << endl;
		temp.pop();
	}*/
	cur = reverStart;
	while (true) {
		cout << str[cur].address << " " << str[cur].data << " " << str[cur].next << endl;
		cur = StringToNum(str[cur].next);
		if (cur == -1)
			break;
	}

	return;
}

int main() {

	string StartAddress;
	int total, rever;
	cin >> StartAddress >> total >> rever;
	init();
	for (int i = 0; i < total; ++i) {
		string s1, s2;
		int d;
		cin >> s1 >> d >> s2;
		//cout << s1 << " " << d << " " << s2 << endl;
		int order = StringToNum(s1);
		//cout << order;
		str[order].address = s1;
		str[order].data = d;
		str[order].next = s2;
	}
	/*cout << "Traverse: " << endl;
	Traverse(StartAddress);
	cout << "SeqTraverse: " << endl;*/

	SeqTraverse(StartAddress, rever);

	return 0;
}

注意点

  • 用一个pre变量来保存当前节点的Address,然后让下一个节点的next节点为pre,进行循环
  • 静态链表存储节点
  • 节点的结构
typedef struct node {
	string address;
	int data;
	string next;
}node;

7-5 一元三次方程

题目描述

给定一个形如ax
3
+bx
2
+cx+d=0的一元三次方程。

已知该方程有三个不同的实数根(根与根之差的绝对值≥10
−6
),且根范围均在[p,q]之间,你需要解出这个方程的三个根。

输入格式

第一行一个整数T(1≤T≤1000),表示有T组数据

接下来T行,每行6个实数,分别表示a,b,c,d,p,q

数据保证:−10
2
≤p,q≤10
2
,且对于∀x∈[p,q],−10
6
≤f(x)≤10
6

输出格式

输出三个实数,表示方程的三个解。

你的答案可以以任意顺序输出。

一个答案被认为是正确的,当且仅当其与标准答案的绝对误差不超过10
−6

输入样例

1
1.000000 -5.000000 -4.000000 20.000000 -10.000000 10.000000

输出样例

-2.000000 2.000000 5.000000

代码

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;

int n;
double a, b, c, d, p, q;

double f(double x) {
	return a * x * x * x + b * x * x + c * x + d;
}

double solution(double left, double right, bool increase) {
	double mid = (left + right) / 2;
	double ans;
	if (increase) {  //递增
		while (right - left > 1e-7) {
			mid = (left + right )/ 2;
			/*if (ans == 0)
				return mid;*/
			if (f(mid) > 0)
				right = mid;
			else
				left = mid;
		}
	}
	else  {  //递减
		 do{
			mid = (left + right) / 2;
			/*if (ans == 0)
				return mid;*/
			if (f(mid) > 0)
				left = mid;
			else
				right = mid;
		}while (right - left > 1e-7);
	}

	return mid;
}

int main() {
	
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> a >> b >> c >> d >> p >> q;
		double a1 = 3 * a;
		double b1 = 2 * b;
		//计算两个极点
		//float m = b1 * b1 - 4 * a1 * c;
		double x1, x2;
		bool ic;
		if (a > 0) {
			ic = true;
			x1 = (-1 * b1 - sqrt(b1 * b1 - 4 * a1 * c)) / (2 * a1);
			x2 = (-1 * b1 + sqrt(b1 * b1 - 4 * a1 * c)) / (2 * a1);
		}	
		else {
			ic = false;
			x2 = (-1 * b1 - sqrt(b1 * b1 - 4 * a1 * c)) / (2 * a1);
			x1 = (-1 * b1 + sqrt(b1 * b1 - 4 * a1 * c)) / (2 * a1);
		}
			
		cout <<setiosflags(ios::fixed)<<setprecision(6) << solution(p, x1,ic) 
			<< " " << solution(x1, x2,!ic) << " " << solution(x2, q,ic) << endl;
	}

	return 0;
}

注意点

  • 先对三次方程求导,得出其两个极点,然后再将[p,q]和两个极点分为三个区间
  • 尽量的少调用f(x)函数,判断答案使用二分答案
  • 要注意判断两个极点的大小,谁在左边谁在右边
  • 判断是否符合答案用
while (right - left > 1e-7) 
  • 不要使用 f(mid) > 1e-6,会超时

[蓝桥杯 2013 国 C] 危险系数

题目背景

抗日战争时期,冀中平原的地道战曾发挥重要作用。

题目描述

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数 D F ( x , y ) DF(x,y) DF(x,y)

对于两个站点 x x x y ( x ≠ y ) , y(x\neq y), y(x=y), 如果能找到一个站点 z z z,当 z z z 被敌人破坏后, x x x y y y 不连通,那么我们称 z z z 为关于 x , y x,y x,y 的关键点。相应的,对于任意一对站点 x x x y y y,危险系数 D F ( x , y ) DF(x,y) DF(x,y) 就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式

输入数据第一行包含 2 2 2 个整数 n ( 2 ≤ n ≤ 1000 ) n(2 \le n \le 1000) n(2n1000) m ( 0 ≤ m ≤ 2000 ) m(0 \le m \le 2000) m(0m2000),分别代表站点数,通道数。

接下来 m m m 行,每行两个整数 u , v ( 1 ≤ u , v ≤ n , u ≠ v ) u,v(1 \le u,v \le n,u\neq v) u,v(1u,vn,u=v) 代表一条通道。

最后 1 1 1 行,两个数 u , v u,v u,v,代表询问两点之间的危险系数 D F ( u , v ) DF(u,v) DF(u,v)

输出格式

一个整数,如果询问的两点不连通则输出 − 1 -1 1

样例 #1

样例输入 #1

7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6

样例输出 #1

2

提示

时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛

代码

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

vector<int> Graph[5000];   //邻接表
bool visited[5000];
int n,m;  //站点数,通道数
int startVex, endVex;  //开始顶点,结束顶点
int del, ans = 0;  //删除的点,总共的关键点
bool reach;  //是否到达


void CreateGraph(){  //创建邻接表
    for(int i = 0; i < m; ++i){
        int u,v;
        cin>>u>>v;
        Graph[u].push_back(v);
        Graph[v].push_back(u);
    }
    
    return;
}


void dfs(int x){
    if(x == endVex || reach){   //到达终点或者到达过终点,直接返回
        reach = true;
        return;
    }
    
    for(int i = 0; i < Graph[x].size(); ++i){
        int cur = Graph[x][i];
        if(cur == del || visited[cur])  //该点被删除或者已经访问过
            continue;
        visited[cur] = true;
        dfs(cur);  //递归
        //visited[cur] = false;  //归还当前节点
    }

}

int main(){
    cin>>n>>m;
    CreateGraph();
    cin>>startVex>>endVex;
    for(int i = 1; i <= n; ++i){
        memset(visited, false, sizeof visited);
        visited[startVex] = true;
        reach = false;
        del = i;
        dfs(startVex);
        if(!reach)  //删除没法到达,说明该点是个关键点
            ans++;

    }

    if(ans == 0)
        cout<<"-1";
    else
        cout<<ans - 1;

    system("pause");
    return 0;
}
  • 枚举每一点,删除该点看是否能从起点走到终点,如果不可以就说明是个关键点
  • 使用邻接表的存储结构存储图

图的遍历

题目描述

给出 N N N 个点, M M M 条边的有向图,对于每个点 v v v,求 A ( v ) A(v) A(v) 表示从点 v v v 出发,能到达的编号最大的点。

输入格式

1 1 1 2 2 2 个整数 N , M N,M N,M,表示点数和边数。

接下来 M M M 行,每行 2 2 2 个整数 U i , V i U_i,V_i Ui,Vi,表示边 ( U i , V i ) (U_i,V_i) (Ui,Vi)。点用 1 , 2 , … , N 1,2,\dots,N 1,2,,N 编号。

输出格式

一行 N N N 个整数 A ( 1 ) , A ( 2 ) , … , A ( N ) A(1),A(2),\dots,A(N) A(1),A(2),,A(N)

样例 #1

样例输入 #1

4 3
1 2
2 4
4 3

样例输出 #1

4 4 3 4

提示

  • 对于 60 % 60\% 60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 \leq N,M \leq 10^3 1N,M103
  • 对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 \leq N,M \leq 10^5 1N,M105

代码

#include<iostream>
#include<vector>
using namespace std;

vector<int> str[100010];   //邻接表
int N,M;  //点数,边数
int maxNum[100010];  //每个点最大可达到的边

void ReverCreate(){  //反向建表
    for(int i = 1; i <= M; ++i){
        int v1,v2;
        cin>>v1>>v2;
        str[v2].push_back(v1);  //反着存该弧
    }
    return;
}

void dfs(int x, int curNum){
    if(!maxNum[x])  //没有访问过
        maxNum[x] = curNum;
    else
        return;
    for(int i = 0; i < str[x].size(); ++i)
        dfs(str[x][i], curNum);
}

int main(){

    cin>>N>>M;
    ReverCreate();
    for(int i = N; i >= 1; --i)
        dfs(i,i);
    for(int i = 1; i <= N; ++i)
        cout<<maxNum[i]<<" ";



    system("pause");
    return 0;
}

注意点

  • 反向建图,即原来是1->2->4<-3,反向建表为1<-2<-4->3,从大到小遍历,每次访问一个之前没访问过的节点就将其最大可到的的数改为当前数字

封锁阳光大学

题目描述

曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

阳光大学的校园是一张由 n n n 个点构成的无向图, n n n 个点之间由 m m m 条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

输入格式

第一行两个正整数,表示节点数和边数。
接下来 m m m 行,每行两个整数 u , v u,v u,v,表示点 u u u 到点 v v v 之间有道路相连。

输出格式

仅一行如果河蟹无法封锁所有道路,则输出 Impossible,否则输出一个整数,表示最少需要多少只河蟹。

样例 #1

样例输入 #1

3 3
1 2
1 3
2 3

样例输出 #1

Impossible

样例 #2

样例输入 #2

3 2
1 2
2 3

样例输出 #2

1

提示

【数据规模】
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 4 1\le n \le 10^4 1n104 1 ≤ m ≤ 1 0 5 1\le m \le 10^5 1m105,保证没有重边。

代码

#include<iostream>
#include<iostream>
#include<cmath>
#include<string>
#include<string>
#include<algorithm>
using namespace std;

int color[20000];  //每一个点的染色
int total[2];  //黑白两种染色各自的点数
int head[20000];
bool visited[20000];
int count=0;

typedef struct node
{
    int t;
    int next;
}str[200000];

void addArc(int a,int b)
{
    count++;
    str[cnt].t=b;
    str[cnt].next=head[a];
    head[a]=count;
}

bool dfs(int node,int color)
{
    if(visited[node])//如果已被染过色
    {
        if(color[node]==color)  //如果仍是原来的颜色,即可行
            return true;
        return false;
    }
    visited[node]=true;
    sum[col[node]=color]++;
    bool tf=true;  
    for(int i=head[node];i!=0 && tf;i=str[i].next)
    {
        tf=tf && dfs(str[i].t,1-color);//是否可以继续染色
    }
    return tf;
}
int main()
{
    bool possible = true;
    int n,m;
    cin>>n>>m;
    
    for(int i = 0; i < m; ++i)
    {
        int u,v;
        cin>>u>>v;
        addArc(u,v);
        addArc(u,v);
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(visited[i])
            continue; 
        total[0]=0;  //两个颜色都还没有,初始化
        total[1]=0;
        if(!dfs(i,0))  //如果不能染色
        {
            cout<<"Impossible";
            possible = false;
            break;
        }
        ans+=min(sum[0],sum[1]);
    }
    if(possible)
        cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值