2022蓝桥杯C++刷题记录

PREV-284 杨辉三角形【第十二届】【省赛】【研究生组】

  • 链接: 杨辉三角题详解Java.
    这个博客讲的算清楚的,就是我对于Check还是一知半解。。。

注意要点

  1. long long 类型是AC的关键!!!
    2022蓝桥杯C++刷题记录_第1张图片
#include
#include
using namespace std;

long long N;
//计算组合数
long long C(int a, int b)
{
	long long sum = 1;
	for (int i = a, j = 1; j <= b; i--, j++)
	{
		sum = sum*i / j;

		if (sum>N)
		{
			return sum;
		}


	}
	return sum;
}


bool check(int k)
{
	long long  rRow = 2 * k;//斜着看的那一行 以第k行为基准 右斜上有 2k个行
	long long  lRow = max(rRow, N);//斜着看的那一行 左斜下是找N和rightRow 最大值
	while (rRow<lRow)
	{
		int mid = rRow + lRow >> 1;


		if (C(mid, k) >= N)
		{
			lRow = mid;
		}
		else
		{
			rRow = mid + 1;
		}
	}
	if (C(lRow, k) !=N )return false;
	else
	{
		cout << (long long)((1 + lRow)*lRow / 2 + (k + 1));
		return true;
	}
}



int main() {
	cin >> N;
	for (int i = 16; ;i--)
	{

		if (check(i))break;
	}
	return 0;

}

试题 算法提高 搬运冰块

要点注意

  • 网上有一个用结构体数组实现的:
#include
#include

using namespace std;

const int N = 100010;

struct Node{
    int t, d;
    bool operator<(const struct Node & n) const{
        return t * n.d < n.t * d;
    }
}node[N];

int n;

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        node[i].t = a;
        node[i].d = b;
    }

    std::sort(node,node + n);

    long long time = 0;
    long long res = 0;
    for(int i = 0; i <= n; i++)
    {
        res += time * node[i].d;
        time += node[i].t;
    }
    cout<< res << endl;
}


  • 我自己用的非关系容器set 只过了6个测试点。。。没找到原因、没有vip 看不了测试数据。。。
#include
#include
#include
using namespace std;


struct iceInfo {
	long long Ti;
	long long Di;
	iceInfo(int t, int d) :Ti(t), Di(d) {}
	bool operator< (const iceInfo &cei) const {
		//以融化体积为基准来进行排序,搬运当前冰块 不会产生损耗
		return this->Ti * cei.Di < this->Di * cei.Ti;  //这个意思是先搬运this 后 cei的损耗 和 先搬运cei后this 的损耗 进行比较。
	}
};
int main() {
	long long N;
	long long sum = 0;//搬完后冰块融化总量
	long long time = 0;//搬运时间
	int  T, D;
	set<iceInfo> sIce;
	
	cin >> N;
	
	for (int i = 0; i < N; i++) {
		cin >> T >> D;
		iceInfo ice(T, D);
		sIce.insert(ice);
	}
	
	for (set<iceInfo> ::iterator it = sIce.begin(); it != sIce.end(); it++) {
		sum += time * it->Di;
		time += it->Ti;
	}
	
	cout << sum << endl;
	
	return 0;
}

试题 算法提高 打包

注意要点

二分法、check函数的逻辑代码理解
参考:打包.

#include
using namespace std;
bool check(int weg[], int mid, int N, int M) {
	int curWeight = 0;
	int curM_Num = 1;
	for (int i = 0; i < N; i++) {
		if ( weg[i] > mid) {//如果超过目标包裹总数 礼物无法以最大包裹容量打包成对应包裹数目。
			return false;
		}

		curWeight += weg[i];

		if (curWeight > mid) {//如果大于当前包裹容量 再打一个新包
			curWeight = weg[i];
			curM_Num++;
		}
	}
	return curM_Num <= M;
}
int main() {
	long long N;
	long long M;
	cin >> N >> M;
	int gifWeg[100010];
	long long right = 0;
	long long left  = 0;
	long long mid   = 0;
	for (int i = 0; i < N; i++) {
		cin >> gifWeg[i];
		right += gifWeg[i];
	}
	//二分法
	while (left < right) {
		mid =  (left + right) / 2;
		if (check(gifWeg, mid, N, M)) {
			right = mid;
		}
		else {
			left = mid + 1;
		}
	}
	cout << left;
	return 0;
}

试题 算法提高 区间覆盖问题

思路:先对vec进行左边界排序(小到大),然后考虑三种情况并依次判断

  • 需要res容器弹出尾部元素,插入新元素的情况
  1. 即将插入尾部的v[i]的左边界res容器的尾部元素左边界 相等那就取右边界最大的那个
  2. res容器元素个数大于2的情况下, 即将插入尾部的v[i]的左边界 小于 res容器中倒数第二个元素的右边界
  • 只需要直接尾部插入元素的情况
    即将插入尾部的v[i]的**左边界 小于 res容器中尾部元素的右边界。
#include
#include
#include
using namespace std;
struct Node {
	long long x;
	long long y;
};
vector<Node> vec;
vector<Node> res;
bool mycmp(Node &a,Node &b) {
	return a.x < b.x;
}

long long coLine(vector<Node>&v, vector<Node>&r,long n) {
	r.push_back(v[0]);
	for (int i = 1; i < v.size(); i++) {
		if ( ((   (r[r.size() - 1].x == v[i].x ||(r.size() >= 2 && r[r.size() - 2].y >= v[i].x))   && r[r.size() - 1].y < v[i].y)) ) {
			r.pop_back();
			r.push_back(v[i]);
		}
		else if (r[r.size() - 1].y >= v[i].x && r[r.size() - 1].y < v[i].y) {
			r.push_back(v[i]);
		}
	}
	if (r[r.size() - 1].y < n) return -1;
	else return r.size();
}

int main() {
	long long n, m;
	cin >> n >> m;
	Node mynode;
	for (long long i = 0; i < m; i++) {
		cin >> mynode.x >> mynode.y;
		vec.push_back(mynode);
	}
	sort(vec.begin(), vec.end(), mycmp);
	cout << coLine(vec, res, n);
}

ADV-1164 和谐宿舍

这题没做出来,留给大家想想,提一点 跟和谐宿舍2有点区别,是求最大木板面积的最小值。。
主要是dp数组定义吧、或者用贪心思想 。

ADV-298 ADV和谐宿舍2

#include
#include
using namespace std;
int dp[101][101];//用i块木板遮住前j幅画的面积最小值 
int mj[101][101];//保存i~j幅画最大的高度值            
int h[101];//保存每幅画的高度  
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>h[i];
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j++)
			mj[i][j]=max(mj[i][j-1],h[j]);//找出i~j幅画的最大高度 
	for(int i=1;i<=n;i++)
		dp[1][i]=mj[1][i]*i;//赋值边界1块板时 
	for(int i=2;i<=m;i++)
		for(int j=1;j<=n;j++)
			if(j<=i)//板数大于画数,每个画用一个板子面积最小 
				for(int m=1;m<=j;m++)
					dp[i][j]+=h[m];
			else
				for(int k=1;j-k>=i-1;k++)//因为不知道前面几个画的分组情况和后几个画为一组面积最小所以需要循环判断
					if(k==1)
							dp[i][j]=dp[i-1][j-k]+mj[j-k+1][j]*k;//第一次赋值,否则直接比较全为0 
					else 
						dp[i][j]=min((dp[i-1][j-k]+mj[j-k+1][j]*k),dp[i][j]);	
	cout<<dp[m][n];
	return 0;
}

试题 算法提高 长度统计

要点注意

  • 何时要开始计算区间(当A元素左边界和B元素右边界存在断层),这时就要考虑对于连续区间序列(无断层)的情况处理。
#include
#include
#include
#include
using namespace std;
struct Node {
	long long x;
	long long y;
};
vector<Node> vecL;
bool mycmp(Node &a,Node &b) {
	return a.x < b.x;
}
int main() {
	int n ;
	cin >> n;
	Node node;
	//vector res;
	stack<int> stN;
	for (int i = 0; i < n; i++) {
		cin >> node.x >> node.y;
		vecL.push_back(node);
	}
	sort(vecL.begin(), vecL.end(), mycmp);//按左边界排序
	//res.push_back(vecL[0]);
	stN.push(0);
	long long left = vecL[0].x;
	long long right = vecL[0].y;
	long long sum = 0;
	for (int i = 1; i < vecL.size(); i++) {
		if (vecL[stN.top()].y >= vecL[i].x &&vecL[stN.top()].y <= vecL[i].y) {//遇到该情况更新右边界
			stN.push(i);
			right = vecL[i].y;
		}
		else if(vecL[stN.top()].y < vecL[i].x){//遇到该情况开始计算覆盖区间,并更新left 和 right
			sum += right - left;
			stN.push(i);
			left = vecL[i].x;
			right = vecL[i].y;
			
		}
		if (i == vecL.size() - 1) {//防止vecL无断层的情况下,没有计算覆盖区间
			sum += right - left;
		}
	}
	cout << sum;
	return 0;
}

试题 历届真题 双向排序【第十二届】【省赛】【研究生组】

要点注意

  • 输出格式要注意,格式不对判错!
  • 本题代码 AC失败 只有60分。。。
#include
using namespace std; 
bool mycmp(int a,int b) {
	return a > b;
}
int main() {
	int n,m,typeN,dIndex;
	cin>>n>>m;
	vector<int> vec;
	for(int i = 1;i <= n;i++) {
		vec.push_back(i); 
	}
//	for(vector::iterator it = vec.begin();it!=vec.end();it++) {
//			cout<< *it;
//		}
	for(int i = 0;i<m;i++) {
		cin>>typeN>>dIndex;
		if(typeN == 0) {
			sort(vec.begin(),vec.begin()+dIndex,mycmp);
		} else {
			sort(vec.begin()+dIndex-1,vec.end());
		}
//		for(vector::iterator it = vec.begin();it!=vec.end();it++) {
//			cout<< *it;
//		}
//		cout<
	
	}
	for(vector<int>::iterator it = vec.begin();it!=vec.end();it++) {
		cout<< *it<<" ";
	} 
	
	 
	return 0;
}

括号序列

题解链接.

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=5003,mod=1e9+7;
int n;
char s[N];
long long f[N][N];//f[i][j]表示前i个序列中左括号比右括号多j个的合法方案数 
long long cal()//计算插入括号合法方案数 
{
	memset(f,0,sizeof f);
	f[0][0]=1;//初始化
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='(') 
		{
			for(int j=1;j<=n;j++)
				f[i][j]=f[i-1][j-1];
		}
		else
		{
			f[i][0]=(f[i-1][0]+f[i-1][1])%mod;//注意0的时候需要特殊处理一下,因为j-1=-1,所以我们不能用化简后的递推式去计算,只能用化简前的递推式去计算
			for(int j=1;j<=n;j++)
				f[i][j]=(f[i-1][j+1]+f[i][j-1])%mod;
		}
		for(int i=0;i<=n;i++)//答案要求我们插入的括号数尽量小,所以要从小向大枚举,右括号的数目是不变的,当加入尽量小的左括号且有解时就返回即可 
			if(f[n][i]) return f[n][i];
	} 
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	long long ans1=cal();//记录左括号的插入方案数 
	reverse(s+1,s+n+1);//将原序列逆置
	for(int i=1;i<=n;i++)
		if(s[i]=='(') s[i]=')';
		else s[i]='(';
	long long ans2=cal();//记录右括号的插入方案数
	printf("%lld",ans1*ans2%mod);
	return 0; 
}

2022蓝桥杯C++刷题记录_第2张图片

你可能感兴趣的:(Cpp,Learning,Road,c++,蓝桥杯)