Codeforces Round #799 (Div. 4)

这篇博客详细解析了三道编程竞赛题目,包括使用双指针解决01序列求和问题,通过三数之和的末尾余数判断是否等于3,以及在序列乘以2的幂次后保持有序的区间计数。文章通过代码示例展示了错误和正确的解题思路,并提供了AC代码。
摘要由CSDN通过智能技术生成

目录

E. Binary Deque

F. 3SUM

G. 2^Sort

E. Binary Deque

题意是给你一个01的序列,让你可以删掉前面的一个数或者后面的一个数,让序列的总和恰好等于m(给定),问最少操作次数

这题一看就知道是双指针,我原来是把每个1的位置记录下来,看看最终的删的那个位置在哪,可惜了,双指针我不好捏,写了好长时间还是不太对。

用二分:把前缀和后缀分别算出来,然后枚举一下后缀,这样就知道前缀应该是多少了,最后求最少的操作次数,然后注意一下边界,因为后缀或者前缀是有可能一次也不操作的,那次数是0,所以那数也是0,边界是[0,n-1],然后还有最后求最少次数的那个,是枚举的位置,而不是数字(数字只是一段区间的和而已),我一开始弄混了QAQ

#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+10;
int f[N],b[N],a[N];
int main(){
	int T;
	cin>>T;
	while(T--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		memset(f,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			f[i]=f[i-1]+a[i];
		}
		if(f[n]<m)
		{
			cout<<"-1"<<"\n";
			continue;
		}
		int t=f[n]-m;
		for(int i=n;i>=1;i--) b[i]=b[i+1]+a[i];
		int res=0x3f3f3f3f;
		for(int i=n+1;i>=0;i--)
		{
			int x=b[i];
			int l=0,r=n+1;
			while(l<r)
			{
				int mid=l+r>>1;
				int y=t-x;
				if(f[mid]>=y) r=mid;
				else l=mid+1;
			}
			if(l>=i) continue;
			if(f[l]+x==t) res=min(res,n-i+l+1);
		}
		cout<<res<<"\n";
	} 
	return 0;
}

F. 3SUM

Problem - F - Codeforces

题意就是,能否选三个数相加使得最后末尾是3

无了个大语,原来写的可能没错,我忘记初始化了,然后就没然后了,没看出来,还以为是代码的问题...

思路就是末尾是3,只需要看每个数的末尾就行了,末尾的数相加取余10看看是不是3就行,然后肯定是0到9里面的数,避免111这种情况,所以个数要++,然后就暴力,有点回溯的思想,在减完之后,要继续搜,恢复一下现场,其他的没啥

#include<iostream>
#include<cstring>
using namespace std;
const int N=100;
int a[N];
int main(){
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		scanf("%d",&n);
		memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++)
		{
			int x;
			scanf("%d",&x);
			int yu=x%10;
			a[yu]++;
		}
		int f=0;
		for(int i=0;i<=9;i++)
		{
			if(a[i])
			{
				a[i]--;
				for(int j=0;j<=9;j++)
				{
					if(a[j])
					{
						a[j]--;
						for(int k=0;k<=9;k++)
						{
							if(a[k])
							{
								a[k]--;
								if((i+j+k)%10==3)
									f=1;
								a[k]++;
							}
						}
						a[j]++;
					}
					
				}
				a[i]++;
			}
		}
		
		if(f) cout<<"YES"<<"\n";
		else cout<<"NO"<<"\n";
	}
	return 0;
} 

G. 2^Sort

​​​​​​Problem - G - Codeforces

给你一个序列,每个数依次乘2的次方,按照区间来如果都能保证前一个数字<后一个数字,就符合条件++,最后问个数

我跟个呆子似的

明明数据范围那么大,我还在用pow,怎么那么死脑筋呢,嗯?,我自己都想到约分,后一个数的二倍比前一个数大就可以,还在pow...

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N];
int main(){
	ll T;
	cin>>T;
	while(T--)
	{
		ll n,len;
		scanf("%lld%lld",&n,&len);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		ll q=n-len;
		ll num=0,k=1;
		while(1)
		{
			ll f=1;
			ll t=a[k],p=1;
			for(ll i=k+1;i<=k+len;i++)
			{
				ll po=pow(2,p);
			//	cout<<a[i]*po<<endl;
				if(a[i]*po<=t)
				{
					f=0;
					break;
				}
				p++;
				t=a[i]*po;
			}
			if(f) num++;
			k++;
			if(k>q) break;
		}
		cout<<num<<"\n";
	}
	return 0;
}
/*
原始的大小关系不会变,看看新的,如果比上一个要大就++ 
先判断一下原始的大小关系 

*/

但是这个代码不是不可以改

这个样子:(超时了QAQ)应该能想到的...

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N];
int main(){
	ll T;
	cin>>T;
	while(T--)
	{
		ll n,len;
		scanf("%lld%lld",&n,&len);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		ll q=n-len;
		ll num=0,k=1;
		while(1)
		{
			ll f=1;
			ll t=a[k];
			for(ll i=k+1;i<=k+len;i++)
			{
			//	cout<<a[i]*po<<endl;
				if(a[i]*2<=t)
				{
					f=0;
					break;
				}
				t=a[i];
			}
			if(f) num++;
			k++;
			if(k>q) break;
		}
		cout<<num<<"\n";
	}
	return 0;
}
/*
原始的大小关系不会变,看看新的,如果比上一个要大就++ 
先判断一下原始的大小关系 

*/

下面是ac代码:符合条件的记为1,不符合记为0,最后看看连续的1有多少,可以构成多少个区间

(看了一位大佬的博客QAQ)

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N],s[N];
int main(){
	ll T;
	cin>>T;
	while(T--)
	{
		int n,k;
		memset(s,0,sizeof(s));
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			if(a[i]*2>a[i-1]) s[i]=1;
			else s[i]=0;
		}
		int t=0,sum=0;
		for(int i=1;i<=n;i++)
		{
			if(s[i]) t++;
			if(!s[i])
			{
				if(t>=k+1) sum+=(t-k);
				t=1;
			}
		}
		if(t>=k+1) sum+=(t-k);
		cout<<sum<<"\n";
	}
	return 0;
}

不过这个思想好熟悉,多多回忆一下,总结总结

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值