第一次写博客(简谈codeforces心得)orz

这一周打codeforces,我发现它出题真的妙~

自己做的题实在是太少了!orz 算法很好玩,都大二了,要加油鸭!冲冲冲

一周刷题记录挂上:

div2的A、B和div3的A、B、C差不多都考思维,每道题都很巧!

div2的C和div3的D就要用些算法知识了(很多都是当场问的dalao

简单写一些dalao教我的题目的解题思路吧!

1.1435C Perform Easily

题目链接:https://codeforces.com/contest/1435/problem/C
题目大意:

吉他上有6根弦,给你a1,a2 , a3 , a4 , a5 , a6 每个弦上附上一个数字,然后给你n (1 ≤ n ≤ 100000)个数,b1, b2, ..., b3 (1 ≤ bi ≤ 109), 并且满足任意b大于a,每个数字都可以放在任意的弦上,

弦数(ai) + 品数 = bj 找所有的数组b都放到弦上后的最大和最小的品数的差值的最小值。

写个题意好累orz)

样例解释:

第一行是各个弦的数字a: 1 1 2 2 3 3

第二行是要放到弦上的数字的数量n: 7

第三行是放上去的n个数字b: 13 4 11 12 11 13 12(有重复数字,放在一个点上即可)

13 --> 放在数为3的弦上 品:10

12 --> 放在数为3的弦上 品:9

12 --> 放在数为3的弦上 品:8

4 --> 放在数为1的弦上 品:3

最大品数和最小品数的差值: 7

解题思路:

因为有1e5个数,可以考虑暴力将所有的数字放在所有的弦上,求距离(O(6e5))放在一个pair数组中,pair的first存品数(方便sort排序),second存j(b数组的下标)。

利用sort使品数排序,然后进行一次从左向右遍历。找到n个下标都存在时的最大和最小值(相当于动态变化的一个n个数字的数组),不断根据它更新答案,找到最小的数组中的最大值-最小值。

这个动态数组找最大和最小值,dalao教我了两种方法:线段树 和 用map(自动排序) 存

而我线段树懒得写(忘的差不多了orz),就用的map。

map存储的是该品数的个数,并且用一个数组v存储当前该数字的数值,当需要更新该数字品数时,把之前的品数v[bb]从v中找到,并在map[v[bb]]--,当改品数的值为0的时候,要erase该品数这点很重要),当num==n的时候,就可以更新ans了!

写完一个题了,耶耶耶!

AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <utility>
#include <map>
using namespace std;
int a[6]; 
map<int,int> mp;
const int maxn = 1e5+5;
int b[maxn];
typedef pair<int,int> PII;
PII s[maxn*6];
int v[maxn];
int main(){
	for(int i=0;i<6;i++){
		scanf("%d",&a[i]);
	}
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		scanf("%d",&b[i]);
	} 
	int len=0;
	for(int i=0;i<6;i++){
		for(int j=0;j<n;j++){
			s[len++]={b[j]-a[i],j};
		}
	}
	sort(s,s+len);
	int num=0;
	int ans=0x3f3f3f3f;
	for(int i=0;i<len;i++){
		int aa=s[i].first;
		int bb=s[i].second;
		if(v[bb]==0){
			num++;
		}
		if(mp[v[bb]]>0)
			mp[v[bb]]--;
		mp[aa]++;
		if(mp[v[bb]]==0){
			mp.erase(v[bb]);
		}
		v[bb]=aa;
		auto it=mp.begin();
		if(num==n){
			ans=min(ans,aa-it->first);
		}
	}
	cout<<ans<<endl;
	return 0;
}

C题太难写了,写个B题吧。思路依然很巧妙~

2.1421B题 Putting Bricks in the Wall

题目链接:https://codeforces.com/contest/1421/problem/B
题目大意:

一个人从S出发,想到达F,他可以上下左右进行移动,但只能选择0或者1进行移动(一旦选择,就不能更改)。必须防止他到达F,你最多可以更改2次(0改成1,或1改成0)。

样例解释:
4
S010
0001
1000
111F
->
S010
0001
1001
111F
//选择 1 或者 0 都无法到达 F
解题思路:

只需要把他的入口和出口改成相反的就可以了(入口全0,出口全1 或 入口全1,出口全0),仔细想一下,真是最多只需要两次改变。(我竟第一眼想的是dfs,bfs,老憨批了┮﹏┭)。

AC代码:

代码可能有点乱。

#include <iostream>
using namespace std;
const int maxn = 205;
char mp[maxn][maxn];
int main(){
	int t;
	cin>>t;
	int n;
	while(t--){
		cin>>n;
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				cin>>mp[i][j];
			}
		}
		char a=mp[1][0];
		char b=mp[0][1];
		
		char c=mp[n-1][n-2];
		char d=mp[n-2][n-1];
		if(a==b&&c==d){//0 1
			if(a==c){
				cout<<"2"<<endl;
				cout<<"1 2"<<endl;
				cout<<"2 1"<<endl; 
			}else{
				cout<<"0"<<endl;
			}		
		}
		else{
			if(a==d&&b==c){
				cout<<"2"<<endl;
				cout<<"1 2"<<endl;
				cout<<n-1<<' '<<n<<endl;
			}   
			else if(a==c&&b==d){
				cout<<2<<endl;
				cout<<"1 2"<<endl;
				cout<<n<<' '<<n-1<<endl;
			}
			else if(a==b){
				cout<<"1"<<endl;
				if(c==a){
					cout<<n<<' '<<n-1<<endl;
				}
				if(d==a){
					cout<<n-1<<' '<<n<<endl;
				}
			}
			else if(c==d){
				cout<<1<<endl;
				if(a==c){
					cout<<"2 1"<<endl;
				}
				if(b==c){
					cout<<"1 2"<<endl;
				}
			}
			
		}
	}
	return 0;
}
posted @ 2020-10-31 09:18  ACHanHan  阅读(223)  评论(0编辑  收藏  举报