CCF CSP certification - 201312

 


 
 

  

201312-1 The number with the most occurrences

topic link

1

The amount of data is small, and the data range is also relatively small. It can be directly violent, by setting the array to record the number of occurrences of the subscript data, and finally traverse the record array to obtain the number with the most occurrences.

#include<iostream>
using namespace std;

int main(){
    
    //暴力 
	int n, flag[10001] = {
    
    0};
	scanf("%d", &n);
	for(int i = 0; i < n; i ++){
    
    
		int a;
		scanf("%d", &a);
		flag[a] ++;
	}
	int m = 0;
	for(int i = 1; i <= 10000; i ++)
		if(flag[m] < flag[i])
			m = i;
	printf("%d", m);
	return 0;
}

 
 

 
 

 
 

201312-2 ISBN number

topic link
2

Short answer questions
You can accept ISBN numbers one by one or in four numbers.

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

int main(){
    
    //注意标识码为X(也就是10)的情况 
	int a[10], b = 0;
	char c;
	scanf("%1d-%1d%1d%1d-%1d%1d%1d%1d%1d-%c", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &a[8], &c);
	for(int i = 0; i < 9; i ++)
		b += a[i] * (i + 1);
	b %= 11;
	if(b == (c == 'X' ? 10 : c - '0'))
		printf("Right");
	else
		printf("%1d-%1d%1d%1d-%1d%1d%1d%1d%1d-%c", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], b == 10 ? 'X' : b + '0');
	return 0;
}

 
 

 
 

 
 

201312-3 largest rectangle

topic link
3


The amount of data is small, and it can be directly solved by violence.
Time complexity: O(n 2 )

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

int main(){
    
    //暴力 
	int n, a[1000], m = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &a[i]) ;
	for(int i = 0; i < n; i ++){
    
    
		int t = a[i];
		for(int j = i; j < n; j ++){
    
    
			t = min(t, a[j]);
			m = max(m, (j - i + 1) * t);
		}
	}
	printf("%d", m);
	return 0;
}

②Monotonous
stack (increment)
is realized by monotonically increasing stack

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

int main(){
    
    //单调栈(递增)
	int n, a[1000], m = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &a[i]) ;
	a[n] = 0;
	stack<int> s;
	for(int i = 0; i <= n; i ++){
    
    
		if(s.empty() || a[s.top()] <= a[i])
			s.push(i);
		else{
    
    
			int t = 0;
			while(!s.empty() && a[s.top()] > a[i]){
    
    
				t = s.top();
				s.pop();
				m = max(m, (i - t) * a[t]);//i - t指的是当前矩阵的宽度,a[t]是当前高度
				//实现单调递增栈
			} 
			s.push(t);
			a[t] = a[i];
		}
	}
	printf("%d", m);
	return 0;
}

The key should be that the following two lines of code are difficult to understand.
s.push(t);
a[t] = a[i];
Why should the last popped position be pushed into the stack again? Because the building is an incremental stack, the heights of the previous stacks can also meet the current height requirements, so the previous area can be retained by pushing the last popped position into the stack without area loss. As follows.
analyze


monotonic stack

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

int main(){
    
    //单调栈 
	int n, a[1000], m = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &a[i]) ;
	a[n] = 0;
	stack<int> s;
	for(int i = 0; i <= n; i ++){
    
    
		if(s.empty() || a[s.top()] < a[i])
			s.push(i);
		else{
    
    
			int t = s.top();
			s.pop();
			int area = a[t] * (s.empty() ? i : i - s.top() - 1);
			m = max(m, area);
			-- i;//不移动i,后面还有有个 i++ 
		}
	}
	printf("%d", m);
	return 0;
}

 
 

 
 

 
 

201312-4 interesting numbers

topic link
4

Dynamic programming
The number placed in the nth digit must be related to the number placed in the first n-1 digits (6 cases) The number
of the first i digits in this state (all) The number of the first i+1 digits in this state

state number transfer equation Situation analysis
a 2 1 If the first i+1 bits are 2, then the first i bits must be 2
b 2,0 b*2+a If the first i+1 digits are 2, 0, then
    the first i digits are all 2, the i+1th digit is 0, the
    first i digit is a mixed string of 2, 0, and the i+1th digit is 2 or 0
c 2,3 c+a If the first i+1 digits are 2, 3, then
    the first i digits are all 2, the i+1th digit is 3, the
    first i digit is a mixed string of 2, 3, and the i+1th digit is 3
d 2,0,1 d*2+b If the first i+1 digits are 2, 0, 1, then
    the first i digits are 2, 0, the i+1th digit is 1,
    the former i digits are 2, 0, 1, and the i+1th digit is 2 or 1
e 2,0,3 e*2+c+b If the first i+1 digits are 2, 0, 3, then
    the first i digits are 2, 0, the i+1th digit is 3,
    the former i digits are 2, 3, the i+1th digit is 0, the
    former i digit is 2, 0, 3, bit i+1 is 0 or 3
f 2,0,3,1 f*2+e+d If the first i+1 bits are 2, 0, 3, 1, then
    the first i bits are 2, 0, 1, the i+1th bit is 3, the
    first i bit is 2, 0, 3, the i+1 bit is
    1 i bit is 2, 0, 3, 1 i+1 bit is 1 or 3
#include<iostream>
using namespace std;

long long a, b, c, d, e, f; 

int main(){
    
    
	//第n位所放置的数一定与前n-1位放置的数有关(6种情况) 
	/*前i位处于该状态个数	状态(全为)	前i+1位处于该状态个数*/
	a = 1;
	b = c = d = e = f = 0;
	int n;
	scanf("%d", &n);
	for(int i = 1; i < n; i ++){
    
    
		long long xb = b * 2 + a;
		long long xc = c + a;
		long long xd = d * 2 + b;
		long long xe = e * 2 + b + c;
		long long xf = f * 2 + d + e;
		
		b = xb % 1000000007LL;
		c = xc % 1000000007LL;
		d = xd % 1000000007LL;
		e = xe % 1000000007LL;
		f = xf % 1000000007LL;
	}
	printf("%lld", f);
	return 0;
}

 
 

 
 

 
 

201312-5 I’m stuck!

topic link
5

dfs depth-first search (violence)
mark all the points that S can reach through dfs,
and try to see if the points that S cannot reach through dfs can reach T. If not, the number will be +1

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

int n, m;//地图行列数
bool flag[50][50], flag1[50][50];//flag1存储S可以到达的点,true为可以到达的点,false为不可以到达的点
int d[][2] = {
    
    -1, 0, 1, 0, 0, -1, 0, 1};//移动方向
vector<string> map;//存储地图
int si, sj, ti, tj;//存储S和T的位置

void dfs(int x, int y){
    
    //深度优先搜索
	int xx, yy;
	flag[x][y] = 1;//标记该点已到达
	
	if(map[x][y] == '+' || map[x][y] == 'S' || map[x][y] == 'T'){
    
    //可以上下左右移动的点
		for(int i = 0; i < 4; i ++){
    
    
			xx = x + d[i][0];
			yy = y + d[i][1];
			if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')//可以走的点
				dfs(xx, yy);
		}
	}
	else if(map[x][y] == '-'){
    
    //可以左右移动的点
		for(int i = 2; i < 4; i ++){
    
    
			xx = x + d[i][0];
			yy = y + d[i][1];
			if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')
				dfs(xx, yy);
		}
	}
	else if(map[x][y] == '|'){
    
    //可以上下移动的点
		for(int i = 0; i < 2; i ++){
    
    
			xx = x + d[i][0];
			yy = y + d[i][1];
			if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')
				dfs(xx, yy);
		}
	}
	else if(map[x][y] == '.'){
    
    //只能向下移动
		xx = x + d[1][0];
		yy = y + d[1][1];
		if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')
			dfs(xx, yy);
	}
}

int main(){
    
    //暴力 
	scanf("%d %d", &n, &m);
	for(int i = 0; i < n; i ++){
    
    
		string s;
		cin >> s;
		map.push_back(s);
	}
	for(int i = 0; i < n; i ++)
		for(int j = 0; j < m; j ++)
			if(map[i][j] == 'S')
				si = i, sj = j;
			else if(map[i][j] == 'T')
				ti = i, tj = j;
	
	dfs(si, sj);
	memcpy(flag1, flag, sizeof(flag));
	
	if(flag[ti][tj]){
    
    
		int cnt = 0;
		for(int i = 0; i < n; i ++)
			for(int j = 0; j < m; j ++){
    
    
				if(flag1[i][j]){
    
    
					memset(flag, 0, sizeof(flag));
					dfs(i, j);
					if(!flag[ti][tj])
						cnt ++;
				}
			}
		printf("%d", cnt);
	}
	else
		printf("I'm stuck!");
	return 0;
}

Guess you like

Origin blog.csdn.net/qq_43448856/article/details/127892877