马上要2022蓝桥杯比赛了,做一下去年的省赛真题。
蓝桥杯2021A组-填空题
A 填空1:
上来就被难到了......有些思维性质。
将这个数作为一个整体进行操作,如果这个数不能拼出,就k--然后跳出循环。
#include<iostream>
using namespace std;
int a[10];
bool check(){
for(int i=0;i<=9;i++){ if(a[i] < 0) return false;}
return true;
}
int main(){
for(int i=0;i<=9;i++) a[i] = 2021;
int k=1;
bool flag = false;
while(1){
int m = k;
int cnt = 0;
while(m > 0){
//int m = k;
int t = m % 10;
//cnt ++;
a[t] --;
m /= 10;
}
if(check() == false) {k--; break;}
k++;
}
cout<<k<<endl;
return 0;
}
B 填空2:
这里对于直线的存储使用的是点斜式,即
(y1-y2)x+(x2-x1)y+(x1y2-x2y1)=0
使用集合set来使得存储的直线为唯一的,最后输出set.size()即可实现对于不同直线的计数。
这里的难点还有对于运算符的重载,不然无法在set中仅从insert操作。
#include<iostream>
#include<set>
#define x first
#define y second
//#include<pair>
using namespace std;
typedef pair<int,int> PII; //点的定义
PII points[410]; //410个点
struct Line{
int a, b, c;
friend bool operator < (const Line &A, const Line &B) {
if (A.a == B.a)return A.b == B.b ? A.c < B.c : A.b < B.b;
return A.a < B.a;
}
};
int gcd(int a, int b) {
//gcd函数,要记住!!!
return b == 0 ? a : gcd(b, a%b);
}
int main(){
int n=20,m=21;
int k=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
points[k] = {i,j};
k++;
}
}
set<Line> v;
//for(int i=0;i<k;i++) cout<<points[i].x <<" "<<points[i].y <<endl;
for(int i=0;i<k;i++){
for(int j=0;j<k && j!=i;j++){
int x1 = points[i].x, y1 = points[i].y;
int x2 = points[j].x, y2 = points[j].y;
//获得两个点的坐标
int a = x1-x2;
int b = y1-y2;
int c = x1*y2-x2*y1;
// cout<<"("<<x1<<","<<y1<<")";
// cout<<"("<<x2<<","<<y2<<")"<<endl;
int GCD = gcd(abs(a), gcd(abs(b), abs(c)));
a /= GCD, b /= GCD, c /= GCD;
Line l = {a,b,c};
v.insert(l);
//这里向集合中插入的时候需要重载运算符
}
}
cout<<v.size()<<endl;
return 0;
}
C 填空3:
这个题看起来比较吓人,实际使用暴力解法的话就是纸老虎。
首先使用遍历求出本数的所有因数,这个大数实际的因数数量只有128个。
之后使用o(n^3)遍历所有的因数进行数量的计算即可。
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
int main(){
ll n = 2021041820210418;
//cin>>n;
vector<ll> v;
//求出所有的非重复因数
for(ll i=1;i*i<=n;i++){
if(n % i == 0){
v.push_back(i);
if(n/i != i) v.push_back(n/i);
}
}
int len = v.size();
long long cnt = 0;
//暴力遍历所有的因数
//for(int i = 0; i < len; i ++) cout<<v[i]<<" ";
for(int i = 0; i < len; i ++){
for(int j = 0;j < len; j ++){
for(int k = 0;k <len; k ++){
if(v[i]*v[j]*v[k] == n) cnt++;
}
}
}
cout<<cnt<<endl;
return 0;
}
D 填空4
最短路问题,该复习了,已经忘光了。
原来最短路也可以使用dp(逃
最后想了想其实这个dp本身就是Bellman_ford算法(
关于最小公倍数和最大公约数的计算公式和计算代码需要继续熟悉了,已经差不多忘记了。
#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e5+10;
int h[N],e[N],ne[N],w[N],idx;
int gcd(int a,int b){ //最大公约数
return b == 0 ? a : gcd(b, a%b);
}
int lcd(int a,int b){ //最小公倍数
return a*b / gcd(a,b);
}
void add(int a,int b,int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
} //添加一条指向a->b的路,权值为c
int main(){
memset(h,-1,sizeof h);
for(int i=1;i<=2021;i++){
for(int j=1;j<=2021;j++){
if(i != j && abs(i-j) <= 21){
//初始化邻接表
add(i,j,lcd(i,j));
}
}
}
//cout<<lcd(15,25)<<endl;
int dp[3000]; //dp[i]表示:从结点1到i的所有路径的最短路长度
memset(dp,0x3f,sizeof dp);
dp[1] = 0;
for(int i=1; i <= 2021;i++){ //遍历点
for(int k = h[i]; k!=-1;k=ne[k]){
//j是当前选中的和i相连的点
//k是idx的值
//v是这条路的长度
int j = e[k];
int v = w[k];
//dp求解最短路
dp[j] = min(dp[j] , dp[i] + v);
}
}
cout<<dp[2021]<<endl;
return 0;
}
E 填空5
看题解说是求最短哈密顿回路,需要用到状态压缩dp,可是状压dp我还没学......
先过了。这个题之后再说
最短哈密顿回路
状态压缩dp
填空题就到这里。大题之前写过几个了,但是还有很多不会,先把填空题总结一下。
填空题的题目图片来自 blog.csdn.net/ljw_study_i…