第十一届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

1.字串排序

不会做,感觉挺难的,有兴趣的可以看下面题解

cpp 复制代码
#include <iostream>
#include <string.h>
using namespace std;
int V;
int len;//符合交换次数V,字符串长度最小值
int now; //当前已经构造好的那一部分字符串逆序对个数
int cnt[27];//当前位置后续部分包含字母a~z个数
int sum[27];//当前构造的部分字符串包含字母a~z个数

//根据V算出字符串长度
int get_max(int len){
    return ((len - (len / 26 + 1)) * (len / 26 + 1) * (len % 26) + (26 - len % 26) * (len / 26) * (len - len / 26)) / 2;
}
//当前放字母x,后边还有n个位置,看是否满足V
bool check(int x , int n)
{
    memset(cnt , 0 , sizeof(cnt));
    int add1 = 0;//在当前位置放x,新增的逆序对个数
    int add2 = 0;//在当前位置放x,后边的逆序对个数最大值
    for(int j = 26 ; j >= x + 1 ; j --) 
      add1 += sum[j];
    //当前位置放x,sum[x]++
    sum[x] ++ ;
    //后边剩余n个位置,遍历
    for(int L = 1 ; L <= n ; L ++)
    {
        int ma = -1;//后续L位置上,放字母新增逆序对个数最大值
        int pos = 0;//放置的字母
        int num = 0;//已经放置的大于第j个字母的字符个数
        for(int j = 26 ; j >= 1 ; j --)
        {
            if(L - 1 - cnt[j] +  num> ma)
            { 
                ma = L - 1 - cnt[j] + num;
                pos = j;
            }
            num += sum[j];
        }
        add2 += ma;
        cnt[pos] ++;//x后续部分包含字母a~z个数
    }
    if(now + add1 + add2 >= V) 
    {
        now += add1; //当前已经构造好的那一部分字符串逆序对个数
        return true;
    }
    else 
    {
        sum[x] -- ;//放弃在当前位置放置x
        return false;
    }
}
int main()
{
  string ans = "";
  cin >> V;
  //从1开始枚举长度,直到len可以产生的最大逆序对大于V
  for(int i = 1 ; ; i ++) 
  {
    if(get_max(i) >= V)
    {
      len = i;
      break ;
    }
  }
  //构造字符串ans,从i开始枚举,枚举每个位置上的字母,字典序小
  for(int i = 1 ; i <= len ; i ++)
  {
    for(int j = 1 ; j <= 26 ; j ++)
    {
      if(check(j , len - i))
      {
        ans += char(j + 'a' - 1);
        break ;
      }
    }
  }
    cout << ans << '\n';
  return 0;
}

2.门派制作

签到水题

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int sum=0;
signed main()
{
	for(int i=2; i<=2020; i++)
	{
		string s=to_string(i);
		for(auto t:s)
		{
			if(t=='2')
			{
				sum++;
			}
		}
	}
	cout<<sum<<endl;
	return 0;
}

3.既分约数

签到水题

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int sum=0;
signed main()
{
	for(int i=1; i<=2020; i++)
	{
		for(int j=1;j<=2020;j++)
		{
			if(__gcd(i,j)==1)
			{
				sum++;
			}
		}
	}
	cout<<sum<<endl;
	return 0;
}

4.蛇形填数

打表找规律

cpp 复制代码
//1
//5
//13
//25
//41
//n*n+(n-1)*(n-1);
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n; 
signed main()
{
	cout<<20*20+19*19<<endl;
	return 0;
}

5.跑步锻炼

日期题,注意周几判断:x%7==1 (额外提一下:类似的方向判断 x%360)和 闰年

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
bool fun1(int t1)
{
	if(t1%4==0 && t1%100!=0 || t1%400==0)
	{
		return true;
	}
	return false;
}
bool fun(int t)
{
	int m[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
	int year=t/10000,month=t%10000/100,day=t%10000%100;
	if(fun1(year)) //判断闰月
	{
		m[2]=29;
	}
	if(year>=2000 && year<=2020 && month>=1 && month<=12 && day>=1 && day<=m[month])
	{
		return true;
	}
	return false;
}
signed main()
{
	int sum=0,x=6;
	for(int i=20000101; i<=20201001; i++)
	{
		if(fun(i)) //是否为合法日期
		{
			if((x%7)==1 || i%10000%100==1) //周1或初1
			{
				sum+=2;
			}
			else
			{
				sum+=1;
			}
			x++; //判断周几
		}
	}
	cout<<sum<<endl;
	return 0;
}

6.七段码

直接把所有情况找出来,最容易理解掌握的方法

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  // 请在此输入您的代码
  int sum = 0;
    
    //有一段二极管发光; a,b,c,d,e,f,g
    int l1 = 7;
    //有两段二极管发光; ab,af,bc,bg,cg,cd,de,eg,ef,fg
    int l2 = 10;
    //有三段二极管发光; abf,abc,abg,afg,afe,bcd,bcg,bgf,bge,cgd,cgf,cge,cde,cdg,deg,def,efg
    int l3 = 16;//       
    //有四段二极管发光; abcd,abcg,abcf,abge,abgf,abfe,afeg,bcde,bcdg,bcgf,bcge,bged,bgef,cdef,cdeg,cdgf,cgfa,cgfe,defg,defa
    int l4 = 20;
    //有五段二极管发光即有两端不发光; ab,ac,ad,ae,af,ag,bc,bd,be,bg,cd,cf,cg,de,df,dg,ef,eg,fg
    int l5 = 19;//
    //有六段二极管发光即有一端不发光; a,b,c,d,e,f,g
    int l6 = 7;//(找一段二极管不发光的:)
    //第七种情况,全部发光
    int l7 = 1;
    
    sum = l1 + l2 + l3 + l4 + l5 + l6 + l7;
    printf("%d\n", sum);
  return 0;
}

7.成绩统计

签到水题,注意使用printf里面的 .lf以此达到四舍五入的效果

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,ans1=0,ans2=0;
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int num;
		cin>>num;
		if(num>=60)
		{
			ans1++;
		}
		if(num>=85)
		{
			ans2++;
		}
	}
	printf("%.lf%\n",100.0*ans1/n) ;
	printf("%.lf%\n",100.0*ans2/n) ;
	return 0;
}
 

8.回文日期

暴力枚举所有情况,寻找回文日期,但是还有一种简单的方法是利用回文特性,通过月日反推出年份,但我感觉有问题(对于闰月判断不是很明确)下面两个代码都给出

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

int d1, d2, sum = 0;

bool fun1(int t1)
{
	if (t1 % 4 == 0 && t1 % 100 != 0 || t1 % 400 == 0)
	{
		return true;
	}
	return false;
}

bool fun(int t)
{
	int m[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int year = t / 10000, month = t % 10000 / 100, day = t % 10000 % 100;
	if (fun1(year)) // 判断闰年
	{
		m[2] = 29;
	}
	if (month >= 1 && month <= 12 && day >= 1 && day <= m[month])
	{
		return true;
	}
	return false;
}

bool isPalindrome(int t)
{
	int original = t;
	int reversed = 0;

	// 判断数字是否回文
	while (t > 0)
	{
		int digit = t % 10;
		reversed = reversed * 10 + digit;
		t /= 10;
	}

	return original == reversed;
}

signed main()
{
	cin >> d1 >> d2;
	for (int i = d1; i <= d2; i++)
	{
		if (fun(i))   // 判断日期合法
		{
			if (isPalindrome(i))   // 判断回文
			{
				sum++;
			}
		}
	}
	cout << sum << endl;
	return 0;
}
cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int date1,date2,sum=0;
signed main()
{
	cin>>date1>>date2; //回文:年=月+日(所有月日组合,看年份是否满足)
	int m[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
	for(int month=1; month<=12; month++)
	{
		for(int day=1; day<=m[month]; day++)
		{
			int year1=day%10*1000+day/10*100+month%10*10+month/10;
			int date=year1*10000+month*100+day; 
			if(date>=date1 && date<=date2)
			{
				sum++;
			}
		}
	}
	cout<<sum<<endl;
	return 0;
}

9.子串分值和

可以去看我的上一篇博客,关于贡献法的题型

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
char s[N];
int pos[27]; //记录该字符上一次出现的位置
signed main()
{
	cin>>s+1; //索引1开始完整读取
	int n=strlen(s+1);
	int res=0;
	for(int i=1; i<=n; i++)
	{	
		int t=s[i]-'a';
		res+=(int)(i-pos[t])*(n-i+1); //n-i+1加一是为了包括自己
		pos[t]=i; //只有最左边的那个会被计入贡献
	}
	cout<<res<<endl;
	return 0;
}

10.平面切分

三种情况:初始状态没有直线,1块平面(切平面算块数)

1.如果新直线和之前的某条直线重合(比如两条一模一样的直线),不增加块数(因为相当于没加新东西)。

2.如果新直线和之前的某条直线平行但不重合,增加 1 块(因为平行直线不会相交,只会多切一刀)。

3.如果新直线和之前的直线相交,每有一个新的交点(注意:多个直线交于同一点只算一个),增加的块数 = 交点数 + 1。

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
double s[1010][2]; //存储直线的A(斜率)和B(截距)
int ans; //存储当前的部分
bool st[1010]; //标记重边
int n;
pair<double,double>p;
signed main()
{
	cin>>n;
	for(int i=0; i<n; i++)
	{
		cin>>s[i][0]>>s[i][1];
		set<pair<double,double>>points; //存储当前直线与之前直线的唯一交点
		for(int j=0; j<i; j++)
		{
			if(st[j]) continue; //重边跳过
			if(s[i][0]==s[j][0]) //斜率相同
			{
				if(s[i][1]==s[j][1]) //截距也相同,重合直线
				{
					st[i]=true;
					break;
				}
				else continue; //平行无交点
			}
			// 计算交点
			p.first = (s[j][1] - s[i][1]) / (s[i][0] - s[j][0]); // 交点的x坐标
			p.second = s[i][0] * p.first + s[i][1]; // 交点的y坐标
			points.insert(p); 
		}
		if(!st[i]) ans+=points.size()+1;
	}
	cout<<ans+1<<endl;
	return 0;
}
相关推荐
小样vvv4 小时前
【面试篇】JVM
jvm·面试·职场和发展
人人题6 小时前
汽车加气站操作工考试答题模板
笔记·职场和发展·微信小程序·汽车·创业创新·学习方法·业界资讯
Jasmin Tin Wei8 小时前
蓝桥杯 web 学海无涯(axios、ecahrts)版本二
前端·蓝桥杯
渗透测试老鸟-九青8 小时前
面试经验分享 | 成都渗透测试工程师二面面经分享
服务器·经验分享·安全·web安全·面试·职场和发展·区块链
SheepMeMe9 小时前
蓝桥杯2024省赛PythonB组——日期问题
python·算法·蓝桥杯
随便昵称9 小时前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
脑子慢且灵9 小时前
蓝桥杯冲刺:一维前缀和
算法·leetcode·职场和发展·蓝桥杯·动态规划·一维前缀和
姜威鱼9 小时前
蓝桥杯python编程每日刷题 day 21
数据结构·算法·蓝桥杯
凯强同学11 小时前
第十四届蓝桥杯大赛软件赛省赛Python 大学 C 组:6.棋盘
python·算法·蓝桥杯
wuqingshun31415912 小时前
蓝桥杯 切割
数据结构·c++·算法·职场和发展·蓝桥杯