codeforces第一周总结

1.TMT Document codeforces 715 div2
https://codeforces.com/contest/1509/problem/B
第二题卡了特别久,完全没有想到如何匹配TMT,呜呜呜我太菜了。这个题的思路是把T分成M前和M后,输入字符串后就将T和M分别弄到两个vector中去,压入的不是字符串,压入的是每个T和M在字符串中的位置。若T和M的数量不是两倍的关系,那就肯定有问题。一共有N个人,那么就有N组TMT,这样我们用贪心的方法,将第1个T 和 第 1 + M个数个T 以及第一个T进行匹配,若是第1个T所处的位置不是M的位置的左边 或 第 1 + M个数个T所处的不是M的位置的右边,那么就说明匹配出问题了。若是都没有出问题,说明就都能排成TMT的形式。具体代码:

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

vector < int > m,t;//用vector来储存T和M的位置
int x,n,flag;
string s;

int main(){
	
	cin >> x;
	while(x--){
		
		cin >> n;
		cin >> s;
		flag = 0;
		m.clear(),t.clear();//在这里卡了好久,原来是用的同一个向量,重复了
		//所以在每次循环时都需要将vector给清空,裂开
		
		for(int i = 0;i < n;i++)
			if(s[i] == 'T')	t.push_back(i);//将每个T的位置压入vector
			else m.push_back(i);//同上
		
		if(t.size() != 2 * m.size()){//如果T的数量不是M的两倍就错了
			cout << "NO" << '\n';
			continue;
		}
		
		for(int i = 0;i < m.size() && !flag;i++)
			if(t[i] > m[i] || t[i + m.size()] < m[i]){
			//若是第1个T所处的位置不是M的位置的左边 
			//或 第 1 +  M个数个T所处的不是M的位置的右边就说明错误了
				cout << "NO" << '\n';
				flag = 1;
			}
			
		if(flag) continue;
		
		cout << "YES" << '\n';//都正确了
	}
	return 0;
}

2.GCD length education codeforces 107 div2
https://codeforces.com/contest/1511/problem/B
这个题也是让我想了好久,呜裂开。不知道标答是什么样子的,但是我的思路是,将a,b,c都当成10的倍数。such as:a = 2,b = 3,c = 2
这样我就将a看成10(不用管a,都看成10的(a-1)倍) b看成110(10的(b-1)倍 + 10的(c-1)倍);这样10和110的最大公约数就是2位数的10了
再比如:a = 3,b = 3,c = 3;将a看成100 b看成200 最大公约数就是3位数的100了。如果a比b大了,就交换数值,计算完结果再交换回来。具体代码:

#include<bits/stdc++.h>
using namespace std;


int t,a,b,c,flag;

int main(){
	
	cin >> t;
	
	while(t--){
		flag = 0;
		cin >> a >> b >> c;
		if(a > b) swap(a,b),flag = 1;
		a = pow(10,a - 1);
		b = pow(10,b - 1) + pow(10,c - 1);
		if(flag) swap(a,b);
		cout << a << " " << b << '\n';
		
	}
	
	return 0;
}

3.Yet Another Card Deck Educational Codeforces Round 107 (Rated for Div. 2) https://codeforces.com/contest/1511/problem/C
这个题就是如果一个颜色的卡被找到了,那么和它同颜色的其他卡就没有被机会选到了,这样就只有五十张不同颜色的卡,就不用担心暴力搜索被超时了。寻找某一个颜色,只需要将这个颜色之前的所有颜色的位置先++,然后将这个颜色的位置发到第一个位置去,然后将这张颜色的卡片的位置和之前的所有颜色的卡片的位置做一个互换就好,这里会用到一个新的函数rotate(first,middle,last)这个的作用就是将从first到middle前一个位置的数和middle到last的前一个位置进行一个互换,such as:
a[10] = {1,2,3,4,5,6,7,8,9,10} rotate(a + 1,a + 3,a + 5} 这样之后a[10]就变成了{3,4,1,2,5,6,7,8,9,10};

具体代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 3e5 + 10;
int n,q,t;
struct car{
	int num,pos;
}card[maxn];//将卡片做成一个结构体,里面放着卡片的颜色和位置

int main(){
	
	cin >> n >> q;
	for(int i = 1;i <= n;i++) cin >> card[i].num,card[i].pos = i;
	
	while(q--){
		
		cin >> t;
		for(int i = 1;i <= n;i++){

			if(card[i].num != t) card[i].pos++;//只要不是要找的这张卡片
			//就将前面卡片的位置全都往后面移一下
			else{//如果是这个颜色的
				cout << card[i].pos << " ";
				card[i].pos = 1;//将这个卡片放到第一个位置
				rotate(card + 1,card + i,card + i + 1);//将这张卡片和前面的全部卡片做一个互换
				break;
			}
		}
	}
	return 0;
}

4.The Sports Festival Codeforces Round #715 (Div. 2)
https://codeforces.com/contest/1509/problem/C
这道题我实在是贪不出来了,可能我天生不适合做一个贪官吧。只要遇到最大值和最小值,那么不管中间的数是什么都会造成一个最大的浪费,所以我们需要将最大的数和最小的数放到两端,这样他们才会最后遇到。我们将输入的数据做一个升序,而因为最大值和最小值迟早会遇到,那么就将dp[1][n]相减,而dp[1][n]是最后才遇到的,所以我们需要找在它们遇到之前的其他数怎么走是最小的开销。这样我们将最小值去掉,用其他数和最大值进行上述操作,或者是将最大值去掉,用其他数和最小值进行上述操作,取两种方案中开销最小的一种。所以转移方程就为dp[1][n] = s[n] - s[1] + min(dp[2][n],dp[1][n-1])。具体代码:

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

const int maxn = 2e3 + 10;
typedef long long ll;
int n,s[maxn];
ll dp[maxn][maxn],ans;

ll dpans(int l,int r){
	
	if(dp[l][r] != -1) return dp[l][r];//记忆化搜索做错了一次 难过
	//以后都需要将记忆化数组弄成-1,只要不是-1就说明已经搜过了,就直接返回答案就好
	
	if(l == r) return 0;//左右端点相等后就变成0,最大小值都是其本身
	dp[l][r] = s[r] - s[l] + min(dpans(l + 1,r),dpans(l,r - 1));
	//状态转移方程
	return dp[l][r];
}

int main(){
	
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> s[i];
	sort(s + 1,s + 1 + n);
	memset(dp,-1,sizeof(dp));//初始化数组
	
	ans = dpans(1,n);
	cout << ans;
	
	return 0;
}

5.AND Sequences Divide by Zero 2021 and Codeforces Round #714 (Div. 2)
https://codeforces.com/contest/1513/problem/B
将所有数据都进行一次与操作,最后得到一个结果h,(这个h要是有两个相同的数与出来的,那么方程就是成立的)查找有几个数据等于这个h,只要有两个以上的数据等于h了,那么将它们放到首尾,只要之间的所有的数据不管如何排列,都不会影响到最后的结果,就比如1,3,5,1 与出来的结果是1,一共有2个1,那么将两个1放到首尾1,3,5,1 这样第一个和后面三个与的结果是相等的。前面都是不怎么严谨的瞎说…方程的具题推断就是,前2个数与的结果一定小于等于前1个数,前1一个数 等于后 n-1个数,后n - 1个数小于等于后n - 2个数,那么只要前2个数等于了后n - 2个数,那么中间是怎么排列的就无所谓了,那么再推断下去,那么只需要第一个数等于最后一个数,那么中间是怎么排列的也无所谓了。要是相等的个数不止两个,那么就从这些数中选两个数进行全排列,再对首尾之间的数进行全排列,这样的结果就是有几种可能了。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 2e5 + 10;
const int modu = 1e9 + 7;
int t,n,a[maxn];
ll h,q;

int main(){
	
	cin >> t;
	while(t--){
		
		q = 0;
		cin >> n;
		
		for(int i = 1;i <= n;i++){
			
			cin >> a[i];
			if(i == 1) h = a[i];
			else h &= a[i];//只有将所有数据与的结果和数组进行比较
			//如果有两个相等的数进行与还是原来本身
			//找到第一个数据和后面所有数据与的结果若是相等的,就找有多少种数据等于第一个数据
			
		}
		
		for(int i = 1;i <= n;i++) if(a[i] == h) q++;
		q *= (q - 1),q %= modu,n -= 2;
		//q个里面选两个
		while(n){
			//全排列n-2
			q *= n;
			q %= modu;
			n--;
			
		}
		
		cout << q << '\n';
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值