专栏文章

8-3陈老师课堂总结--程皓楠

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miojaah3
此快照首次捕获于
2025/12/02 20:07
3 个月前
此快照最后确认于
2025/12/02 20:07
3 个月前
查看原文

P1102 A-B 数对

函数代替手写

1. lower_bound(a+1,a+1+n,x)-a
这个函数能够求出最小的满足a[i]>=x的地址,但我们要求下标,所以要用地址-地址=下标
2. upper_bound(a+1,a+1+n,x)-a
这个函数能够求出最小的满足a[i]>x的地址,但我们要求下标所以要用地址-地址=下标

题目思路

我们可以把A-B=C转化成A-C=B,然后一定要变成有序序列,然后用二分第一个大于b的下标-第一个大于等于b的下标从而求出b的个数

AC代码

CPP
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int a[N];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,c;
	cin>>n>>c;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+1+n);
	int sum=0;
	for(int i=1;i<=n;i++)sum+=(upper_bound(a+1,a+1+n,a[i]-c)-lower_bound(a+1,a+1+n,a[i]-c));
	cout<<sum;
	return 0;
}

A-CF1006C Three Parts of the Array

简化题意

给定一个长度为n的数列d,你需要将它分成从左到右3个连续的子数列,每个数字属于且仅属于其中一个子数列。要求第一个数列的元素值之和sum1等于第三个数列元素之和sum3。第二个数列可以没有元素。求sum1的最大值。

题目思路

通过题意,我们可以发现我们重点研究的是sum1和sum3,sum2并无大用。看到和,我们立即可以立即想到前缀和,然而这道题的数据大小又让我们想到O(nlogn),所以这道题的算法我们可以猜到是前缀和+二分
我们可以先算出数列d的前缀和,然后判断若二分出第一个大于等于s[n]-s[i+1]的值的下标>=i并且s[n]-s[i+1]要等于[1,二分的值的下标]之和就废止

AC代码

CPP
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+5;
int s[N];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,ans=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		s[i]=s[i-1]+x;
	}
	for(int i=1;i<=n;i++)
	{
		int l=i+1,r=n;
		int pos=lower_bound(s+1,s+1+n,s[r]-s[l-1])-s;
		if(pos>=i&&s[pos]==s[r]-s[l-1])ans=s[i];
	}
	cout<<ans;
	return 0;
}

B-Glider

题目思路

这道题目我们可以枚举起跳的点,在这之前,我们用两个前缀和求出变的距离和不变的距离,然后二分高度,由于下降的距离是已知的,所以我们要取不下降距离的最大值,每次都用二分高度的下标-起跳点,取最大和,最后输出用不下降最大距离+下降距离

AC代码

CPP
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int s[N],e[N],sum[N],pre[N];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i]>>e[i];
		if(i>1)sum[i]=sum[i-1]+(s[i]-e[i-1]);
		pre[i]=pre[i-1]+(e[i]-s[i]);
	} 
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(sum+i+1,sum+1+n,sum[i]+k)-sum-1;
		ans=max(ans,(pre[pos]-pre[i-1]));
	}
	cout<<ans+k;
	return 0;
}

C - Romantic Glasses

题目思路

用两个前缀和求出奇数下标和,还有偶数下标和,然后用桶统计sum1[r]-sum2[r]的差出现了几次,找出重复的差,若有就输出YES,等循环结束后,若还没输出YES,则输出NO

AC代码

CPP
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+5;
int a[N],sum1[N],sum2[N];
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		map<int,int> mp;
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			if(i%2==1)
			{
				sum1[i]=sum1[i-1]+a[i];
				sum2[i]=sum2[i-1];
			}
			else
			{
				sum2[i]=sum2[i-1]+a[i];
				sum1[i]=sum1[i-1];
			}
		}
		bool f=1;
		for(int r=0;r<=n;r++)
		{
			mp[sum1[r]-sum2[r]]++;
			if(mp[sum1[r]-sum2[r]]>1)
			{
				cout<<"YES\n";
				f=0;
				break;
			}
		}
		if(f)cout<<"NO\n";
		mp.clear();
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...