序列 sequence

本文介绍了一个关于数列的数学问题,要求找出所有数的平均数小于等于中位数的组合方式。通过排序、枚举和优化的meet-in-the-middle算法,解决了这一经典问题,最终给出了具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创题,没有提交的地方。

一、题目

众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

勇太有一个长度为 n 的数列,现在六花可以从中选出若干个数(不可以不取)。她的方案需要满足她选出的所有数的平均数小于等于中位数。现在勇太想让六花求出满足条件的方案数。

注:数列长度为偶数的时候,中位数为排序后最中间的两个数的平均数。

当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?

二、解法

先把所有数从小到大排序,接着可以枚举中位数是哪两个数的平均数,假设是l和r(长度为奇数的情况相当于l=r),然后我们给数列中所有数减去平均数,那么这时的方案数就等于从[1,l),(r,n]这两个区间中选出相同数目的数使得它们的和小于0。

我们可以把待选的数给单独拿出来(即把区间[l,r]的数删掉),如果原来它的下标小于l,把么权重为1否则权重为-1。问题就相当于给出若干个数,你要选出一些数使得它们的权重和为0且权值和小于0,这是一个经典的meet in middle的问题。我们可以把数均等的分成两部分,分别处理出两部分中的所有选取方法,然后根据权重分组,每组排序之后就能统计答案了。

上述算法的时间复杂度是∑i=1n(n−i)∗2(n−i)/2∗(n−i)/2=O(2n/2∗n2)\sum_{i=1}^n (n-i)*2^{(n-i)/2}*(n-i)/2=O(2^{n/2}*n^2)i=1n(ni)2(ni)/2(ni)/2=O(2n/2n2),这样是会超时的(除非你的常数足够好)。

我们发现我们没有必要排序,我们可以在枚Q举的时候使用归并的方法,直接让每组有序,这样就能减少一个n的复杂度。

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int w[50],x[50];
int A[50],n,N,li;
vector<long long>L[50],R[50],t;
void solve1(int lim){
	L[0].push_back(0);
	for (int now=1;now<=lim;now++)
		for (int i=min(li,now);i;i--){
			t=L[i]; L[i].clear(); int l=0,r=0;
			while (l<L[i-1].size()&&r<t.size())
				if (L[i-1][l]+x[now]<=t[r]){
					L[i].push_back(L[i-1][l]+x[now]); l++;
				} else {
					L[i].push_back(t[r]); r++;
				}
			while (l<L[i-1].size()) L[i].push_back(L[i-1][l]+x[now]),l++;
			while (r<t.size()) L[i].push_back(t[r]),r++;
		}
}
void solve2(int lim){
	R[0].push_back(0); int now=0; li=0;
	for (int kk=n;kk>lim;kk--){
		if (w[kk]==-1){
			now++; li=max(li,now);
			for (int i=now;i;i--){
				t=R[i]; R[i].clear(); 
				vector<long long>::iterator l=R[i-1].begin(),r=t.begin();
				while (l!=R[i-1].end()&&r!=t.end())
					if ((*l)+x[kk]<=(*r)){
						R[i].push_back((*l)+x[kk]); l++;
					} else {
						R[i].push_back((*r)); r++;
					}
				while (l!=R[i-1].end()) R[i].push_back((*l)+x[kk]),l++;
				while (r!=t.end()) R[i].push_back((*r)),r++;
			}
		} else 
			for (int i=0;i<now;i++){
				t=R[i]; R[i].clear(); int l=0,r=0;
				while (l<R[i+1].size()&&r<t.size())
					if (R[i+1][l]+x[kk]<=t[r]){
						R[i].push_back(R[i+1][l]+x[kk]); l++;
					} else {
						R[i].push_back(t[r]); r++;
					}
				while (l<R[i+1].size()) R[i].push_back(R[i+1][l]+x[kk]),l++;
				while (r<t.size()) R[i].push_back(t[r]),r++;
			}
	}
}
long long solve(){
	int mid=n/2;
	for (int i=0;i<=n;i++) L[i].clear();
	for (int i=0;i<=n;i++) R[i].clear();
	solve2(mid);
	solve1(mid);
	long long ans=0;
	for (int now=0;now<=li;now++){
		int k1=R[now].size()-1;
		for (int i=0;i<L[now].size()&&k1>=0;i++){
			while (k1>=0&&R[now][k1]+L[now][i]>0) k1--;
			ans+=k1+1;
		}
	}
	return ans;
}
int main(){
    freopen("sequence.in", "r", stdin);
    freopen("sequence.out", "w", stdout);
	scanf("%d",&N);
	for (int i=1;i<=N;i++) scanf("%d",&A[i]);
	for (int i=1;i<=N;i++) A[i]*=2;
	sort(A+1,A+N+1);
	long long ans=0;
	for (int l=1;l<=N;l++)
		for (int r=l;r<=N;r++){
			n=0; int mi=(A[l]+A[r])/2;
			li=min(li,min(l-1,N-r));
			if (l-1>=N-r){
				for (int i=1;i<l;i++){
					w[++n]=1; x[n]=A[i]-mi;
				}
				for (int i=r+1;i<=N;i++){
					w[++n]=-1; x[n]=A[i]-mi;
				}
			} else {
				for (int i=r+1;i<=N;i++){
					w[++n]=1; x[n]=A[i]-mi;
				}
				for (int i=1;i<l;i++){
					w[++n]=-1; x[n]=A[i]-mi;
				}
			}
			ans+=solve();
		}
	printf("%lld\n",ans);
	return 0;
}
			
### 关于 Unreal Engine 动画序列的使用教程 #### 创建和编辑动画序列 在Unreal Engine中,动画序列是用于存储角色或其他物体运动数据的关键组件。这些序列可以被创建并应用于骨架网格体来实现复杂的动作效果[^1]。 为了新建一个动画序列,在内容浏览器中右键点击空白处,选择`Animation Sequence`选项,并指定目标骨骼结构作为基础。之后可以在Sequencer窗口内调整曲线、关键帧以及应用各种修改器以完善动画表现形式。 对于已有的动画资源文件(.fbx),可以通过导入方式快速生成对应的Sequence资产。这使得外部制作好的模型可以直接利用起来而无需重新构建整个过程。 ```cpp // C++代码示例:加载特定名称的动画序列 UAnimSequence* LoadAnimSeq(FString AnimName){ static ConstructorHelpers::FObjectFinder<UAnimSequence> Asset(TEXT("/Game/Animations/" + AnimName)); return Asset.Object; } ``` #### 应用动画序列至角色 当拥有合适的动画序列后,下一步就是将其关联给相应的Actor对象。通常情况下这是指将它设置为某个Skeletal Mesh Component的一部分属性值之一——即`Current Animation`字段下拉菜单里的项。 如果希望动态改变正在播放的内容,则可通过Blueprints可视化脚本或者C++编程接口来进行实时切换操作。例如,在游戏中响应玩家输入事件触发不同的奔跑姿态变化等场景非常实用。 ```blueprint // Blueprint节点逻辑示意: Set AnimInstance->Montage_Play(SelectedAnimMontage, PlayRate); ``` #### 高级特性与优化技巧 除了基本的功能外,还支持诸如循环模式设定、时间轴缩放等功能来自定义回放行为;另外也允许用户自定义采样率从而平衡性能开销同视觉质量之间的关系[^2]。 值得注意的是,合理规划好各个状态间的过渡机制同样重要。借助Blend Space工具能够轻松达成平滑自然的效果转换体验,进一步提升整体沉浸感水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值