Codeforces Round 1061 (Div. 2) A-D题解

赛时还剩一个小时开D题,虽然第一眼就看出来怎么写了
(可能因为最近在练状压dp),但是因为题目理解错了,还以为自己想错了,就写了个假的算法,到最后判然醒悟的时候已经就剩20分钟了,最后神志不清交了D四次罚时。等比赛结束冷静之后发现是下标有问题(经典状压从0还是从1开始写错了)
最后赛后测评结束后再提交就通过了。总之很遗憾吧,但感觉自己确实进步了不少,一开始D都是写不出来的,后来第一次赛时all in出了D,到现在能差点时间就能赛时4题。

A. Pizza Time

https://codeforces.com/contest/2156/problem/A

初见端倪,发现出题人喜欢分组是吧

code

#include <bits/stdc++.h>
#define intt long long
#define N
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
void solve()
{
	cin>>n;
	if(n<=2) cout<<0;
	else
	{
		if((n-2)%2) cout<<(n-2)/2+1;
		else cout<<(n-2)/2;
	}
	cout<<endl; 
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

B. Strange Machine

https://codeforces.com/contest/2156/problem/B

对于没有除2的操作来说,我们需要特殊处理,以免跑到 O ( n ) O(n) O(n)
对于有除2的操作来说,我们可以把减法和预处理,然后暴力模拟,最多不超过 O ( l o g n ) O(log_n) O(logn)

code

#include <bits/stdc++.h>
#define int long long
#define N 30
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m,a[N];
string s;
void solve()
{
	cin>>n>>m;
	cin>>s;
	vector<int> v;
	bool spj=0;
	int sum=0;
	for(int t=0;t<s.size();++t)
	{
		if(s[t]=='A')
		{
			sum+=1;
		}
		else
		{
			if(sum) v.push_back(sum);
			sum=0;
			v.push_back(0);
			spj=1; 
		}
	}
	if(sum) v.push_back(sum); 
	for(int t=1;t<=m;++t)
	{
		int u1,ans=0;
		cin>>u1;
		if(spj)
		{
			int now=0,pos=0;
			while(u1)
			{
				 
				if(!v[pos])
				{
					u1/=2;
					++now;
				}
				else
				{
					if(u1<=v[pos])
					{
						now+=u1;
						u1=0;
					}
					else
					{
						now+=v[pos];
						u1-=v[pos];
					}
				}
				if(pos==v.size()-1) pos=0;
				else pos++;
				
//				debug(pos)
//				debug(now)
//				debug(u1)
//				cout<<endl;
			}
//			cout<<"answer";
			cout<<now<<endl; 
		}
		else
		{
//			cout<<"answer";
			cout<<u1<<endl; 
		}
	}
	
}
signed main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

C. Maximum GCD on Whiteboard

https://codeforces.com/contest/2156/problem/C

分组构造题,和A熟悉的配方。
假设我们已经确定了最大公约数,我们只需要快速找出有多少个序列中的元素可以通过题目的方法变的合法。只要合法的个数满足题目要求就行。
对于一个数字我们可以发现一个结论,假设当前确定的最大公约数为k,那么只有当它为k,2k,3k,或者>=4k才是合法的元素(即本来就合法,或是可以通过题目的分组变得合法)。
所以我们从大到小枚举最大公约数,然后用树状数组或线段树维护>=4k的元素即可。
时间复杂度 O ( n l o g n ) O(nlog_n) O(nlogn)

code

#include <bits/stdc++.h>
#define intt long long
#define N 200005
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
int tr[N],num[N];
void yadd(int u)
{
	for(;u<=n;u+=u&(-u))
	{
		tr[u]++;
	}
}
int yask(int u)
{
	int sum=0;
	for(;u;u-=u&(-u))
	{
		sum+=tr[u];
	}
	return sum;
}
void solve()
{
	cin>>n>>m;
	for(int t=0;t<=n;++t) tr[t]=0,num[t]=0;
	
	for(int t=1;t<=n;++t)
	{
		int u1;
		cin>>u1;
		yadd(u1);
		++num[u1];
	}
	for(int t=n;t>=1;--t)
	{
		int tot=num[t];
		if(t*2<=n) tot+=num[t*2];
		if(t*3<=n) tot+=num[t*3];
		if(t*4<=n) tot+=yask(n)-yask(4*t-1);
		if(tot+m>=n)
		{
			cout<<t;
			cout<<endl;
			break;
		}
	}
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}

D. Find the Last Number

https://codeforces.com/contest/2156/problem/D

首先,我们可以先想最暴力的解法,那肯定是枚举1~n每一个数字,然后用它对n-1个数询问即可。
但是这样子询问次数肯定会超时。
我们发现,上述暴力的思路是每次可以排除一个数字,最后排除了n-1个数字,最后就剩下唯一确定的数字,那么我们可以借鉴上边的思路,比如和1进行&运算,可以发现我们直接排除了一半的答案(其实这一步也可以理解为判断是偶数和奇数),这样子我们就能优化暴力思路(一次枚举排除了一半的答案),以此类推,我们发现对剩下的数字采用相同的策略也同样可以筛选掉一半的元素,这样子我们通过每次一半一半的筛掉,就能确定最后的元素。
询问的总次数是
s u m = n + n / 2 + n / 4 + n / 8 + . . . + n / 2 y < = 2 ∗ n sum=n+n/2+n/4+n/8+...+n/2^y<=2*n sum=n+n/2+n/4+n/8+...+n/2y<=2n

code

#include <bits/stdc++.h>
#define intt long long
#define N 200005
#define debug(x) cout<<#x<<":"<<x<<" ";

using namespace std;
//using namespace __gnu_pbds;
int T,n,m;
int num[35][2],tot[35][2];
bool valid[N],validpos[N];
vector<int> v1,v2; 

void solve()
{
	cin>>n;
	int ans=0;
	for(int t=1;t<=n;++t) valid[t]=0,validpos[t]=0;
	for(int t=0;t<=32;++t)
	{
		num[t][0]=num[t][1]=tot[t][0]=tot[t][1]=0;
	}
	
	int len=0;
	for(int t=0;(1<<t)<=n;++t)
	{
		++len;
	}
	for(int t=1;t<=n;++t)
	{
		for(int i=0;i<len;++i)
		{
			if((t>>i)&1)
			{
				++num[i+1][1];
			}
			else ++num[i+1][0];
		}
	}
	
	int u1=1,pos=1;
	while(pos<=len)
	{
		bool spj;
		v1.clear();
		v2.clear();
		for(int t=1;t<=n;++t)
		{
			if(valid[t])
			{
				if(t&u1)
				{
					++tot[pos][1];
				}
				else ++tot[pos][0];
			}
		}
		for(int t=1;t<=n-1;++t)
		{
			if(validpos[t]) continue;
			else
			{
				cout<<"? "<<t<<" "<<u1<<endl;
				cin>>spj;
				if(spj)
				{
					v1.push_back(t);
					++tot[pos][1];
				}
				else 
				{
					v2.push_back(t);
					++tot[pos][0];
				}
			}
		}
		
		if(num[pos][1]==tot[pos][1])
		{
			 
			for(int t=1;t<=n;++t)
			{
				if(valid[t]) continue;
				if(t&u1)
				{
					valid[t]=1;
				}
			}
			for(auto i:v1)
			{
				validpos[i]=1;
			}
		}
		else
		{
			ans|=u1; 
			for(int t=1;t<=n;++t)
			{
				if(valid[t]) continue;
				
				if(t&u1) continue;
				else 
				{
					valid[t]=1;
				}
			}
			for(auto i:v2)
			{
				validpos[i]=1;
			}
		}
		u1<<=1;
		++pos;
	}
	cout<<"! "<<ans<<endl;
}
int main()
{
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}
### Codeforces Round 1005 Div. 2 A-F Problem Solutions #### A. Money Change 为了处理货币转换问题,可以将所有的金额都转化为分的形式来简化计算。通过遍历输入数据并累加各个部分的金额,最后求得剩余的钱数并对100取模得到最终结果[^2]。 ```cpp #include <iostream> using namespace std; int main() { int s, xi, yi; cin >> s; int total_cents = 0; for (int i = 0; i < s; ++i) { cin >> xi >> yi; total_cents += xi * 100 + yi; } cout << (s * 100 - total_cents) % 100 << endl; } ``` #### B. Odd and Even Pairs 此题目要求找到至少一对满足条件的索引:要么是一个偶数值的位置,或者是两个奇数值位置。程序会读入测试次数`t`以及每次测试中的数组长度`n`及其元素,并尝试找出符合条件的一对索引输出;如果没有这样的组合则返回-1[^3]。 ```cpp #include <cstdio> int main() { int t, n, num; scanf("%d", &t); while (t--) { int evenIndex = 0, oddIndex1 = 0, oddIndex2 = 0; scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &num); if (num % 2 == 0 && !evenIndex) evenIndex = i; else if (num % 2 != 0) { if (!oddIndex1) oddIndex1 = i; else if (!oddIndex2) oddIndex2 = i; } if ((evenIndex || (oddIndex1 && oddIndex2))) break; } if (evenIndex) printf("1\n%d\n", evenIndex); else if (oddIndex1 && oddIndex2) printf("2\n%d %d\n", oddIndex1, oddIndex2); else printf("-1\n"); } return 0; } ``` 由于仅提供了前两道题的具体描述和解决方案,在这里无法继续给出完整的C至F题解答。通常情况下,每一道竞赛编程题都有其独特的挑战性和解决方法,建议查阅官方题解或社区讨论获取更多帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值