1916_C. Training Before the Olympiad_数学_余数_归纳_奇数偶数_贪心_博弈论

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

void solve()
{
	int n,a,cnt=0;
	cin>>n;

	long long s=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a;
		s+=a;
		
		if(a&1)
			cnt++;
		
		if(i==1)
			cout<<a<<" ";
		else
			cout<<s-(cnt/3+(cnt%3==1))<<" ";
	}
	cout<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

上面是修饰过后的代码,感觉非常简短,没用数组啥的,只用了一些变量,一层循环写完了,也没有把过程一步一步分开写

下面是最开始的代码

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N=2e5+10;

int a[N];//cnt 存奇数的个数
long long s[N];

void solve()
{
	int n;
	cin>>n;
	
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s[i]=s[i-1]+a[i];
		
		if(a[i]%2!=0)
			cnt++;
		
		if(i==1)
			cout<<a[i]<<" ";
		else
		{
			long long ans=s[i];
			ans=ans-(cnt/3+(cnt%3==1));
//			if(i==4)
//				cout<<endl<<"4%3==1的数值是"<<(cnt%3==1)<<endl;
			cout<<ans;
			if(i!=n)
				cout<<" ";
		}
	}
	cout<<endl;
	
//	for(int i=1;i<=n;i++)
//		cin>>a[i];
//	
//	cout<<a[1]<<" ";
//	
//	int cnt=0;
//	for(int i=1;i<=n;i++)
//	{
//		s[i]=s[i-1]+a[i];
//		if(a[i]%2!=0)
//			cnt++;
//	}
//	for(int i=2;i<=n;i++)
//	{
//		int ans=s[i];
//		ans=ans-(cnt/3+(cnt%3==1));
//		if(i==2)
//			cout<<"i=2的时候奇数的个数是:"<<endl<<cnt<<endl;
//		cout<<ans;
//		if(i!=n)
//			cout<<" ";
//	}
//	cout<<endl;
//	
//	memset(a,0,sizeof a);
//	memset(s,0,sizeof s);
	//memset(cnt,0,sizeof cnt);
	//判断奇数偶数个数就行
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

中间错了几次,主要是因为 long long ,还有我想要用布尔值直接表示,就不需要用一个条件判断,但是之前没有用好,少加了个括号,然后不断输出调试才发现问题

该题我写了好久,看了一下榜单,很多分数很高的人,几分钟就写出了该题

我先是模拟样例理解题意,然后是自己弄几个数据归纳规律

发现全是偶数的话,答案就是总和

两个奇数相加,答案是偶数,两个偶数相加,答案也是偶数,一个奇数一个偶数,这样的组合会让答案减小一

先开始的人要使得答案尽可能大,就是要尽可能避免使用 一个奇数,一个偶数这种组合

另一个人要使得答案尽可能小,就是要尽量使用一个奇数一个偶数的组合,使用一次,可以使得答案减小一,两个奇数的和是偶数,事实上偶数不会影响答案,可以通过模拟样例发现这个规律

我们首先统计奇数的个数,我开始以为是奇数的个数的奇偶性影响答案,试了几个数据发现不是这回事,我试了有7,8,9,10,11,12,13,14,15个奇数对应应该减小的答案,发现是,3,2,3,4,3,4,5,4,5

三个一个循环,想让答案大就每一次操作两个奇数,想让答案小就每次操作一个奇数一个偶数,两个奇数操作后变成了一个偶数,刚好和后面一个奇数操作,这就是博弈!

注意任何操作之后,两个数字都会变成一个偶数,因为向下取整之后乘了二

归纳观察可以发现,奇数出现次数记作 cnt 的话,cnt/3 表示的是需要减少的答案的数目, cnt%3 的结果是 1 的话,表示多了一个奇数,还需要多减小 1 的答案(我的代码里面用了一个比较简短的写法,记得要加括号)

统计奇数个数,a&1 表示的是该数字是奇数,因为二进制表示的话,奇数的二进制的最低位一定是 1 ,1&1==1,偶数的最低位一定是 0,比用模二判断要快一些,因为计算机底层用的是二进制编码

有 1e5 个 1e9 的数字,所以他们的和一定超过了 int 能表示的数据范围,所以要使用 long long

相关推荐
lxyzcm6 分钟前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
蜀黍@猿24 分钟前
C/C++基础错题归纳
c++
古希腊掌管学习的神27 分钟前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca28 分钟前
洛谷 P1706 全排列问题 C语言
算法
浊酒南街33 分钟前
决策树(理论知识1)
算法·决策树·机器学习
雨中rain39 分钟前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
就爱学编程41 分钟前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条1 小时前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学
Schwertlilien1 小时前
图像处理-Ch4-频率域处理
算法
北国无红豆1 小时前
【CAN总线】STM32的CAN外设
c语言·stm32·嵌入式硬件