1042 模拟

permutation 排列
题目大意: 洗牌 。54张牌的初始序列为[1,…54]。给出每次改变的位置,即将第i个位置的牌挪到第a[i]个位置上。 循环往复。 输出最终的序列。

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

char s[5] = {\'S\',\'H\', \'C\', \'D\', \'J\'};
int k; //k<=20 重复次数
vector<int> v(55), a(55),temp;

void shuchu(){
	for(int i=1;i<=54;i++){
		if( i != 1 ){
			cout<<\" \";
		}
		cout<<s[(a[i]-1)/13];
		a[i]%13 == 0? cout<<13 : cout<<a[i]%13;
	}
}

int main(){
	cin>>k;
	for(int i=1;i<=54;i++){
		cin>>v[i];
		a[i] = i;
	} 
	for(int i=1;i<=k;i++){
		temp.clear();
		temp.resize(55);
		for(int i = 1;i<=54;i++){
			temp[v[i]] = a[i];
		}
		for(int i = 1;i<=54;i++){
			a[i] = temp[i];
		}
	}
	shuchu();
	return 0;
}

1043 排序二叉树

题目大意: 已知先序遍历,说明他是排序二叉树还是排序二叉树的镜像(即交换左右子树); 若是 排序二叉树还是排序二叉树的镜像 ,则输出 后序遍历。 若不是,输出NO。
思路:

  • 如果第二个数字小于(大于等于)第一个数字,则推测是排序二叉树(镜像二叉树),因为第二个数字是左孩子,一定比根节点小。(排除递增或者递减序列,这样根本无法判断)。
  • 然后将序列重新排序,因为是排序二叉树,因此中序遍历一定是个递增(递减)序列。找到第一个大于根节点的数字,则是右子树的开始,递归查找左右子树。对于排序二叉树(镜像)来说,若左子树出现大于等于(小于)根节点的值,则输出NO,若右子树出现小于(大于等于)根节点的值,则输出NO。
  • 若输出YES,递归输出后序遍历。值得注意的是,在每次在中序遍历的数组中查找根节点的时候,排序二叉树找的是 第一个 等于 前序遍历的第一个值 得数。镜像二叉树找的是 最后一个 等于 前序遍历的第一个值 得数。

关于一个排序二叉树的小插曲 >>>点击<<<

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

int n; //<=1000
vector<int> pre, in, post;
bool flag = true; 
int is = 0;
 
void check1(int root, int end){
	if(root >= end) return;
	int p = root + 1, rst;
	while( p < end && pre[root] <= pre[p] ) p++;
	for(rst = p; p < end; p++){
		if(pre[root] <= pre[p]){
			flag = false;
			return;
		}
	}
	check1(root+1, rst); //检查左
	check1(rst, end); //检查右 
	return;
}

void check2(int root, int end){
	if(root >= end) return;
	int p = root + 1, rst;
	while( p < end && pre[root] > pre[p] ) p++;
	for(rst = p; p < end; p++){
		if(pre[root] > pre[p]){
			flag = false;
			return;
		}
	}
	check2(root+1, rst); //检查左
	check2(rst, end); //检查右 
}

void reverse(int prep,int preq, int inp, int inq){
	if(prep >= preq || inp >= inq) return;
	int inroot;
	for(inroot = inp; inroot < inq; inroot++){
		if(pre[prep] == in[inroot]){
			if(is == 1){ // 如果是镜像,找到相同的值得最后一个 
				for(int i = inroot+1; i<inq; i++){
					if(pre[prep] != in[i]){
						inroot = i-1;
						break;
					}
				}
			}
			break;
		}
	}
	reverse(prep+1, prep + 1 + inroot - inp , inp, inroot );
	reverse(prep + 1 + inroot - inp, preq, inroot +1, inq );
	post.push_back(pre[prep]);
}

int main(){
	
	cin>>n;
	pre.resize(n);
	in.resize(n);
	for(int i=0;i<n;i++){
		cin>>pre[i];
	}
	in = pre;
	
	if(pre[0] <= pre[1]){//是镜像 
		is = 1;
		sort(in.begin(), in.end(), greater<int>() ); //从大到小即是中序遍历。
		check1(0,n); 
	}else{
		sort(in.begin(), in.end()); //从小到大即是中序遍历。
		check2(0,n); 
	}
	if(!flag){
		cout<<\"NO\"<<endl;
	}else{
		cout<<\"YES\"<<endl;
		reverse(0,n,0,n);
		for(int i=0;i<n;i++){
			if(i!=0){
				cout<<\" \";
			}
			cout<<post[i];
		}
	}	 
	return 0;
} 

1044 尺取法

题目大意: 找到所有和为m的连续子序列。若找不到, 找到大于m的最小和 ,输出所有结果。

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

typedef struct node{
	int p,q;
}node;

int main(){
	int n, m; // n<=10^5, m<=10^8
	cin>>n>>m;
	vector<int> v(n);
	for(int i=0;i<n;i++){
		cin>>v[i];
	}
	
	bool flag = false;
	int sum = 0;
	for(int p=0,q=0; p<n && q<n+1; ){ 
		if( sum == m){
			cout<<p+1<<\"-\"<<q<<endl;
			flag = true;
			sum -= v[p];
			p++;
		}else if(sum < m){
			sum += v[q];
			q++;
		}else{
			sum -= v[p];
			p++;
		}
	}
	
	if(!flag){
		vector<node> ans;
		int sum = 0, min = 99999999;
		for(int p=0,q=0; p<n && q<n+1; ){ 
			if( sum > m){
				//cout<<sum<<\" \"<<min<<endl;
				if(sum < min){
					min = sum;
					ans.clear();
					node temp;
					temp.p = p+1, temp.q = q;
					ans.push_back(temp);
				}else if(sum == min){
					node temp;
					temp.p = p+1, temp.q = q;
					ans.push_back(temp);
				}
				sum -= v[p]; 
				p++;
			}else if(sum < m){
				sum += v[q];
				q++;
			}else{
				sum -= v[p];
				p++;
			}
		}
		for(int i=0; i<ans.size(); i++){
			cout<<ans[i].p<<\"-\"<<ans[i].q<<endl;
		} 
	}
	return 0;
} 

1045 动态规划

题目大意: 给出一串数字A,和一串数字B;想让A中的数字只能是B中的数字的最长子字符串。找最长不下降子字符串。 结果不唯一,只需输出最长的长度。例如:

  • 给出A= {2 2 4 1 5 5 6 3 1 1 5 6}, B= {2 3 1 5 6}。
  • 找出的最长字符串为 {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6},和{2 2 3 1 1 5 6}。
  • 因此答案为7。

思路: 将每个喜欢的颜色按照输入顺序编号,转化成最长不下降子序列。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
	int n, m, x;
	cin>>n>>m; //n<=200,颜色编号从1...n 
	vector<int> fav(n+1); 
	bool visit[205];
	for(int i=1;i<=m;i++){
		cin>>x;
		fav[x] = i; //存入编号 
		visit[x] = true;
	} 
	int l; // l<= 10^4
	cin>>l;
	vector<int> v(l+1);
	int num = 0;
	for(int i=0;i<l;i++){
		cin>>x;
		if(visit[x] == true){ //剔除不喜欢的 
			v[num++] = fav[x];
		}
	}
	
	//按照最长不下降子序列 
	int dp[10005];
	int ans = 0;
	for(int i = 0; i < num; i++){
		dp[i] = 1;
		for(int j = 0; j < i; j++){
			if(v[i] >= v[j]){
				dp[i] = max(dp[i], dp[j]+1);
			}
		}
		ans = max(dp[i], ans);
	}
	
	cout<<ans;
	
	return 0;
} 
收藏 打印