24暑期第三次训练C组题解

A 津津的储蓄计划

模拟题, 按题意模拟即可.

void func()
{
	int jin = 0,mom = 0;
    // jin为津津手上的钱, mom为妈妈手上存的钱. 
	vector<int> pay(12);// 开一个vector数组, 存12个月的开支(也可以在线计算)
	for(auto &i : pay)	cin >> i;// auto遍历, 后面会详细讲. 
	for(int i=0;i<12;++i)
	{
		jin += 300;
		jin -= pay[i];
		if(jin < 0)
		{
			cout << -(i+1) << '\n';//下标从0开始,答案需+1
			return;
		}
		mom += (jin / 100)*100;// 津津手上整百的钱, 交给妈妈保管. 
		jin %= 100;
	}
	int ans = jin + mom*1.2;// 答案直接输出会cout浮点型, 在cout加强制类型转换也可. 
	cout << ans << '\n';
}

auto遍历:

  1. auto
    自动识别类型
    视频讲解
    auto n = 10;
    // n被赋值整型数据, auto自动将n声明为整型变量. 
    
  2. auto遍历
    视频讲解
    for(类型 变量 : 容器名)
    // 可以遍历一个容器(从头到尾)
    
    string s1;
    for(chat i : s1) cout << i;
    //此时可遍历s1, 将s1输出. 
    // 因为auto可以自动推断类型, 所以这类遍历方法可以都用auto代替
    
    vector<int> a(12);
    for(auto &i : a)    cin >> i;
    // 变量前放'&'时, 可对元素读写, 不加则只能读. 
    

B 校门外的树

模拟题, 因为数据较小可以直接开数组存树, 也可以用区间合并.

void func()
{
	int l,m,ans = 0;
	cin >> l >> m;
	int u,v;
	bool tree[N];
	memset(tree,1,sizeof tree);//初始化,种树. 后续会有memset()函数用法
	while(m--)
	{
		cin >> u >> v;
		for(int i=u;i<=v;++i)	tree[i] = 0;// 砍树
	}
	for(int i=0;i<=l;++i)
	{
		ans += tree[i];// 清点总数
	}
	cout << ans << '\n';
}

memset()

时间复杂度O(n)
给数组初始化为一个固定值, 此处就给bool数组初始化为1.
但是int数组只能初始化为-1, 0, 或者无穷大. 详情请看此篇博客
区间合并做法:

void func()
{
	int l,m;
	cin >> l >> m;
	vector<pair<int,int>> a(m),b;
	for(int i=0;i<m;++i)	cin >> a[i].x >> a[i].y;
	sort(a.begin(),a.end());
	int u = a[0].x,v = a[0].y;
	for(int i=1;i<m;++i)
	{
		if(a[i].x <= v)
		{
			if(a[i].y > v)	v = a[i].y;
		}
		else
		{
			b.push_back({u,v});
			u = a[i].x,v = a[i].y;
		}
	}
	b.push_back({u,v});
	int ans = l+1;
	for(auto &i : b)
	{
		ans -= (i.y - i.x + 1);
	}
	cout << ans << '\n';
}

区间排序和二元组自行了解.

C 杨辉三角

因为是数组, 所以每个元素从左上一个和正上的和组成.

void func()
{
	int n;
	cin >> n;
	int a[n][n];
	memset(a,0,sizeof a);
	for(int i=0;i<n;++i)
	{
		a[i][0] = 1;
		a[i][i] = 1;
	}
	for(int i=2;i<n;++i)
	{
		for(int j=1;j<i;++j)
		{
			a[i][j] = a[i-1][j-1] + a[i-1][j];
		}
	}
	for(int i=0;i<n;++i)
	{
		for(int j=0;j<=i;++j)	cout << a[i][j] << ' ';
		cout << '\n';
	}
}

D Special Characters

相同字符连续情况, 在个数为1时, 不产生特殊字符. 在个数大于等于2时, 这组字符的收尾构成特殊字符. 所以可推得: 特殊字符两两出现, n为奇数时, 必不可能.

void func()
{
	int n;
	cin >> n;
	if(n&1)// 判断n的奇偶
	{
		cout << "NO\n";
		return;
	}
	else	cout << "YES\n";
	n /= 2;// 因为字符两辆出现, 所以可以/2, 方便后续计算. 
	// 可以根据n奇偶选择A/B
	while(n)
	{
		n --;
		n & 1 ? cout << "BB" : cout << "AA";// 三目运算符
		// 因为只要不同字符, 所以用AB两种即可. 
	}
	cout << "\n";
}

位运算&

算竞里会经常用到位运算, 尤其很多题目专门考察位运算.
& 与
| 或
^ 异或
! 非
原理自查.

三目运算符

条件 ? 结果1 : 结果2

条件为真时, 执行结果1. 为假执行结果2.

E Strange Splitting

可以只有一个元素, 这时其范围为0.
这样另一组只需要范围不为0即可.
给出已经是升序. 只要第一个数和最后一个数不相同则可选出范围不同的两组(a[0] == a[n-1]代表所有元素均相等).

void func()
{
	int n;
	cin >> n;
	vector<int> a(n);
	for(auto &i : a)	cin >> i;
	if(a[0] == a[n-1])
	{
		cout << "NO\n";
		return ;
	}
	cout << "YES\n";
	if(a[n-1] == a[1])// 如果第二个数和最后一个相等, 那么选择这组, 范围也为0. 
	{
		// 选择0~n-2 和 n-1
		for(int i=0;i<n-1;++i)	cout << 'R';
		cout << 'B';
	}
	else
	{
		// 选择0 和 1~n-2
		cout << 'R';
		for(int i=1;i<n;++i)	cout << 'B';
	}
	cout << '\n';
}

F Stickogon

正多边形, 由3+条边组成. 每3条边可以组成一个正多边形(一个正六边形可以组成两个正三角形).

void func()
{
	int n,ans = 0;
	cin >> n;
	map<int,int> cnt;// 清点每种个数
	int stp;
	while(n--)
	{
		cin >> stp;
		cnt[stp]++;
	}
	for(auto &i : cnt)// auto遍历, 这时每个i是一个二元组. 
	{
		ans += (i.second/3);
	}
	cout << ans << '\n';
}

G Card Exchange

首先, 对于每组牌, 牌数越多, 越有可能进行更多的交换.
然后, 每组牌获得相同数的牌, 这组牌越多, 越可能进行更多交换.
所以, 只需要每次对最多牌数的组操作, 将其加入第二多的组.
这时排序是动态的, 因为需要实时的最多组, 所以要用的优先队列(堆).
stl的priority_queue, 自行学习.

struct PII// 构造二元组
{
	int x,y;
	bool operator < (const PII &i)	const// 重载预算符, 使得堆先根据二元组的第二个元素从大到小排, 再第一个元素从大到小排. 
	{
		return (y == i.y ? x < i.x : y < i.y);
	}
};

void func()
{
	int n,k,ans = 0;
	cin >> n >> k;
	map<int,int> cnt;
	int stp;
	while(n--)
	{
		cin >> stp;
		cnt[stp]++;
	}
	priority_queue<PII> pq;// 优先队列(堆)
	// 此处也可以不重载, 用stl的二元组, 只需将牌数放第一个元素即可. 
	for(auto &i : cnt)	pq.push({i.x,i.y});
	while(pq.top().y >= k)
	{
		auto stp1 = pq.top();pq.pop();
		stp1.y -= k;
		pq.push(stp1);
		auto stp2 = pq.top();pq.pop();
		stp2.y += (k-1);
		pq.push(stp2);
	}
	while(pq.size())
	{
		ans += pq.top().y;
		pq.pop();
	}
	cout << ans << '\n';
}

构造结构体和重载运算符

结构体: c的语法, 不记得自学.
重载运算符: 如上是重载 < 运算符的方法, 其他自行了解.
对于< , ab两个元素, 如果a < b为真, 那么a在前, b在后.
这里的小于是重载后的小于.
重载小于号在需要排序的题很常用, 尤其易和堆配合.

H Least Product

可以分为三种情况:

  1. 出现了0, 这时r为0. 需要进行0次操作.
  2. 全是正数或者偶数个负数, 这时r>0, 将任意元素改为0即可时r最小, 等于0.需要进行一次操作.
  3. 奇数个负数, 这时r < 0. 需要进行0次操作.
void func()
{
	int n;
	cin >> n;
	vector<int> a(n);
	for(auto &i : a)	cin >> i;
	int cnt = 0;
	bool sign = false;
	for(auto &i : a)
	{
		if(i == 0)	sign = true;
		if(i < 0)	cnt++;
	}
	if(cnt&1 || sign)	cout << 0 << '\n';
	else	cout << 1 << '\n' << 1 << ' ' << 0 << '\n';
}

I 选数

难点在于怎么选k个数, 用dfs, 自行了解, 教程很多.

int n,k,ans;
int a[N];
void dfs(int,int,int);
bool slove(int);

int main(void)
{
	cin >> n >> k;
	for(int i=0;i<n;++i)	cin >> a[i];
	for(int i=0;i<n;++i)	dfs(i,1,a[i]);
	cout << ans << '\n';
	return 0;
}

void dfs(int z,int cnt,int sum)// 传入分别是: 前一个加上第几个数, 已经加了几个数, 总和. 
{
	if(cnt == k)	ans += slove(sum);
	else
	{
		for(int i=z+1;i<n;++i)	dfs(i,cnt+1,sum+a[i]);
	}
}

bool slove(int z)// 判断是否是素数. 
{
	if(z == 1)	return false;
	for(int i=2;i<=z/i;++i)
	{
		if(z % i == 0)	return false;
	}
	return true;
}

DFS

如图为DFS遍历树.

J Peter的烟

福利题, 原本在这里是道很难的数学题, 但是太蓝桥杯了被改掉了.
夹带私活 —— 《死一样的抽过》

void func()
{
	int n, k;
	int butt = 0,ans = 0;// 烟蒂数和抽数
	cin >> n >> k;
	butt += n;
	ans += n;
	while(butt >= k)
	{
		ans += (butt/k);// 
		butt = (butt/k + butt%k); //新换的烟的烟蒂和换掉后余下烟蒂
	}
	cout << ans << '\n';
}
posted @   zerocloud01  阅读(111)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示