2020年蓝桥杯国赛C++B组试题

👉 一 扩散——广度优先搜索

题目链接

在这里插入图片描述
注意坐标可能是负数就可以了,因此,我们把初始点整体右移一定距离,然后常规BFS。

#include<bits/stdc++.h>
using namespace std;
string s11,s22 ,s1 ,s2;
int N = 3000;
int a[8000][8000];
int times[8000][8000];
typedef pair<int,int> P;
P beg,cur,next,end;
queue<P> Q;

int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1}};
int main(){
	
	a[N][N] = 1;
	a[2020+N][11+N] = 1;
	a[11+N][14+N] = 1;
	a[2000+N][2000+N] = 1;
	beg.first = N;beg.second = N;
	Q.push(beg);
	beg.first = 2020+N;beg.second = 11+N;
	Q.push(beg);
	beg.first = 11+N;beg.second = 14+N;
	Q.push(beg);
	beg.first = 2000+N;beg.second = 2000+N;
	Q.push(beg);
	int tx, ty;
	while(!Q.empty()){
		cur= Q.front();Q.pop();
		if(times[cur.first][cur.second] == 2020){
			break;
		}
		for(int i = 0 ; i < 4; ++i){
			tx = cur.first + dir[i][0];
			ty = cur.second + dir[i][1];
			if(a[tx][ty] == 1){
				continue;
			}
			else{
				times[tx][ty] = times[cur.first][cur.second] + 1;
				a[tx][ty] = 1;
				next.first = tx; next.second = ty;
				Q.push(next);
			}	
		}
		
	}
	int ans = 0;
	for(int i = 0 ; i < 8000; ++i){
		for(int j = 0 ; j < 8000; ++j){
			if(a[i][j]){
				ans++;
			}
		}
	}
	cout<<ans;  //20312088
	return 0;
}

👉 二 阶乘约数——数论

题目链接
在这里插入图片描述
思路

根据数论知识:任意一个正整数都可以写成若干质数的乘积,X = p1^α1 * p2^ α2 …… * pk^αk
那么约数的个数p = (α1+1)*(α2 +1)*…*(αk +1)
有了上述基础,那么n!的约数个数也就是先把n!转为若干质数的乘积,并统计每一个质数的个数,然后根据公式求得约数个数即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
map<int , int > m;
signed main(){
	//统计n个数的若干质数乘积。 
	for(int i = 2; i <=100;++i){
		int t = i;
		//统计每一个数t的若干质数乘积 
		for(int j = 2 ; j <= t ;){
			if(t % j == 0){
				t = t / j;
				m[j] ++; 
			}else{
				j ++;
			}
		}	
	}
	map<int,int>::iterator it = m. begin();
	//根据公式求得约数。
	int ans = 1; 
	for(;it!=m.end();++it){
		ans = ans*(it->second+1);
	}
	cout<<ans;
	return 0;
}

👉 三 本质上升序列——动态规划

题目链接
在这里插入图片描述
思路
据说90%的字符串问题都可以用 动态规划(dp) 解决哦

动态规划三大步, 1.设状态表示方程 2.找状态转移方程 3.状态方程初始化
dp 思路:题目要求去重递增子序列的个数,不妨拆开来做,即先求递增子序列的个数,再考虑去重。
1.假设dp[i]表示前i个的递增子序列的个数(通常为题目所求结果即为状态表示方程)
2. 由于是递增子序列,那么 需满足前提 dp[i] > dp[j],有 dp[i] = dp[i] + dp[j]。 显然j < i。
3.因为每一个str[i]是一个递增子序列,那么初始化 dp[i] = 1;

现在考虑去重,在第2个中的状态转移方程中,我们只考虑了dp[i] > dp[j]的情形,那么如果dp[i] == dp[j]和dp[i]<dp[j]的情形呢,

  1. 对于dp[i] < dp[j],不符合题意,continue掉;
  2. 对于dp[i] == dp[j],说明此时有两个字符是相同的,那么dp[j]与dp[j]前面的子序列组成的情况 和 dp[i]与dp[j]前面子序列组成的情况必然会出现重复统计,例如 a n n,dp[0] = 1 dp[1] = 3 dp[2] = 3 ,这里重复统计了一次an的递增子序列,即a、 n、 an ,所以有dp[i] = dp[i] - dp[j]。

因此,总的状态转移为:

 if(str[i] > str[j]){
 	dp[i] = dp[i] + dp[j]; 
} else if(str[i] == str[j]){
	dp[i] = dp[i] - dp[j]; 
}
#include<bits/stdc++.h>
using namespace std;
#define int long long 
set<string> sets;

string str;
string s;
// 共有2的200次方种方案, 铁定超时,所以下面用dp做。 
void dfs(int i){
	if(i >= str.size()){
		sets.insert(s);
		return;
	}
	if(str[i] > s[s.size()-1]){  //可选 
		s+=str[i];
		dfs(i+1);
		s.erase(s.size()-1);
	}
	dfs(i+1);  //不选 
}
int dp[1000];
signed main(){
	str = "tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
//	dfs(0);
//	cout<<sets.size() - 1;
	dp[0] = 1;
	for(int i = 1 ; i < str.size() ; ++i){
		dp[i] = 1;  //每个本身有一个。 
		for(int j = 0; j < i; ++j){
			if(str[i] > str[j]){
				dp[i] = dp[i] + dp[j]; 
			} else if(str[i] == str[j]){
				dp[i] = dp[i] - dp[j];  //去重 假如有 a n n ,那么dp[1] = 3, dp[2] = 3 因此是重复统计了一次an的子序列,即a n an 
			}
		}
	} 
	int ans = 0;
	for(int i = 0 ;i < str.size();++i) ans += dp[i];
	cout<<ans; 
	return 0;
} 

👉 四 玩具蛇——DFS

题目链接
在这里插入图片描述
确定了一个位置后,下一个位置可能的情况就知道了,这就可以用深度优先搜索来做。题目的意思就是要求1-16依次连续放入方格中的方案数量。

#include<bits/stdc++.h>
using namespace std;
int dir[4][2] = { {0,1}, {1,0},{-1,0},{0,-1}};
int vis[10][10];
int cnt;
int k;
void dfs(int x, int y){
	if(k == 16){
		cnt ++;
//		for(int i = 1; i <= 4; ++i){
//			for(int j = 1; j <= 4; ++j){
//				cout<<vis[i][j]<<" ";
//			}
//			cout<<'\n';
//		}
//		cout<<'\n';
		return;
	}
	for(int i = 0 ; i < 4; ++i){
		int tx = x + dir[i][0]; 
		int ty = y+dir[i][1];
		if(tx>=1 &&tx <= 4 && ty >= 1 && ty <= 4 && vis[tx][ty] == 0){
			k++;
			vis[tx][ty] = k; 
			dfs(tx, ty);
			k--;
			vis[tx][ty] = 0;
		}
	}
}

int main(){
	for(int i = 1; i <= 4; ++i){
		for(int j = 1; j <= 4; ++j){
			k = 1;
			vis[i][j] = 1;
			dfs(i,j);
			vis[i][j] = 0;
		}
	}
	cout<<cnt;
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值