牛客多校2 - Greater and Greater(bitset优化暴力)

本文介绍了一种使用bitset优化的算法,解决在给定数组中寻找满足特定条件的子数组问题。通过排序和双指针技巧,将时间复杂度从n*m级别降低至O(n+m),实现高效解算。

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

题目链接:点击查看

题目大意:给出一个长度为 n 的数组 a ,再给出一个长度最大为 m 的数组 b,现在问在 a 中所有长度为 m 的子数组中,有多少个子数组满足每个相应的元素都大于数组 b

题目分析:很显然的一个暴力时间复杂度是 n * m 级别的,高达 6e9 ,但是除以 32 后,时间复杂度好像就在可行范围内了,所以需要利用 bitset 优化一下

参考博客:https://www.cnblogs.com/whitelily/p/13311327.html

首先对于数组 b 的每个元素维护一个长度为 n 的bitset,假设 bit[ i ] 是 b[ i ] 所维护的的 bitset,bit[ i ][ j ] = 1 当且仅当 a[ j ] 大于等于 b[ i ]

不难看出,如果长度为 m 的 a 的一个子数组满足条件,需要满足 a[ i ] >= b[ j ] && a[ i + 1 ] >= b[ j + 1 ] && ... && a[ i + m - 1 ] >= b[ j + m - 1] ,换句话说需要 bit[ i ][ j ] = bit[ i + 1 ][ j + 1 ] = ... =  bit[ i + m - 1 ][ j + m - 1 ] = 1 同时成立,如果将 bit[ i ][ j ] 放在一个二维平面中去,显然上述条件涉及到的 m 个 bit 元素位于一条斜率为 1 的斜线上,换句话说,上述条件也等同于 bit[ i ][ j ] & bit[ i + 1 ][ j + 1 ] >> 1 & ... & bit[ i + m - 1 ][ j + m - 1 ] >> ( m - 1 ) 成立,这样在求出 bit 数组后, m 个 bit 数组进行 与 运算后 1 的个数就是答案了

但构造 bit 数组朴素的话需要 n * m 的时间复杂度,显然是不可以的,不难发现,如果 b[ i ] > b[ j ] ,当 bit[ j ] 已经转移完毕时,bit[ i ] 仅需要在 bit[ j ] 的基础上再转移就可以了,基于此,我们可以将数组 a 和数组 b 排序后双指针转移,这样时间复杂度就降低到了 O( n + m )

因为维护 m 个 bit 数组的 与 运算还是需要 n * m 的时间复杂度的,所以总的时间复杂度为 O(\frac{n*m}{w})

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=150000+100;

bitset<N>ans,t;

vector<pair<int,int>>a,b;
 
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
	{
		int num;
		scanf("%d",&num);
		a.emplace_back(num,i);
	}
	for(int i=0;i<m;i++)
	{
		int num;
		scanf("%d",&num);
		b.emplace_back(num,i);
	}
	sort(a.begin(),a.end());
	sort(b.begin(),b.end());
	int pos=n-1;
	ans.set();
	for(int i=m-1;i>=0;i--)
	{
		while(pos>=0&&a[pos].first>=b[i].first)
		{
			t.set(a[pos].second);
			pos--;
		}
		ans&=t>>b[i].second;
	}
	printf("%d\n",ans.count());










    return 0;
}

 

资源下载链接为: https://pan.quark.cn/s/140386800631 通用大模型文本分类实践的基本原理是,借助大模型自身较强的理解和推理能力,在使用时需在prompt中明确分类任务目标,并详细解释每个类目概念,尤其要突出类目间的差别。 结合in-context learning思想,有效的prompt应包含分类任务介绍及细节、类目概念解释、每个类目对应的例子和待分类文本。但实际应用中,类目和样本较易导致prompt过长,影响大模型推理效果,因此可先通过向量检索缩小范围,再由大模型做最终决策。 具体方案为:离线时提前配置好每个类目的概念及对应样本;在线时先对给定query进行向量召回,再将召回结果交给大模型决策。 该方法不更新任何模型参数,直接使用开源模型参数。其架构参考GPT-RE并结合相关实践改写,加入上下文学习以提高准确度,还使用BGE作为向量模型,K-BERT提取文本关键词,拼接召回的相似例子作为上下文输入大模型。 代码实现上,大模型用Qwen2-7B-Instruct,Embedding采用bge-base-zh-v1.5,向量库选择milvus。分类主函数的作用是在向量库中召回相似案例,拼接prompt后输入大模型。 结果方面,使用ICL时accuracy达0.94,比bert文本分类的0.98低0.04,错误类别6个,处理时添加“家居”类别,影响不大;不使用ICL时accuracy为0.88,错误58项,可能与未修改prompt有关。 优点是无需训练即可有较好结果,例子优质、类目界限清晰时效果更佳,适合围绕通用大模型api打造工具;缺点是上限不高,仅针对一个分类任务部署大模型不划算,推理速度慢,icl的token使用,用收费api会有额外开销。 后续可优化的点是利用key-bert提取的关键词,因为核心词语有时比语意更重要。 参考资料包括
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值