[unknown OJ] ZZH与背包

一、题目

点此看题

二、解法

一看就是折半搜索,但是左边要排序右边要二分的, O ( 2 20 × q log ⁡ ) O(2^{20}\times q\log) O(220×qlog)

这种题往往就是卡掉排序的复杂度,我们可以考虑用归并排序来卡。

假设我们维护的是一个有序数组,那么我们加一个 v v v 的时候这个数组就变成了两个。一个是原来的数组,一个是每个元素都加上了 v v v 的数组,那么这两个数组就可以用归并,所以第一部分的复杂度变成 O ( 2 s ) O(2^s) O(2s)

第二部分其实也可以用归并,一共有 q 2 n − s q2^{n-s} q2n−s 个询问,每次加入一个 v v v 时可以用相同的方法归并起来,复杂度是 O ( q 2 n − s ) O(q2^{n-s}) O(q2n−s),然后我们用一个指针就可以一次处理所有询问。

那么当 2 s = q 2 40 2^s=\sqrt{q2^{40}} 2s=q240 ​ 时最优,时间复杂度是 O ( q 2 40 ) O(\sqrt{q2^{40}}) O(q240 ​),为了卡空间我干了一些好事

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std; 
#define int long long
const int M = (1<<25)+5;
const int K = 1e14;
const int K2 = 1e18;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,q,o,a[M],b[M],c[M],p[M],v[45],ans[505];
struct node
{
	int x,id,fl;
	node(int X=0,int I=0,int F=0) : x(X) , id(I) , fl(F) {}
	bool operator < (const node &b)
	{
		return x<b.x;
	}
}s[1005];
void merge(int *a,int *b,int &m1,int m2)
{
	int i=1,j=1,t=0;
	while(i<=m1 && j<=m2)
	{
		if(a[i]%K<=b[j]%K) c[++t]=a[i],i++;
		else c[++t]=b[j],j++;
	}
	while(i<=m1) c[++t]=a[i],i++;
	while(j<=m2) c[++t]=b[j],j++;
	m1=t;
	for(int i=1;i<=m1;i++)
		a[i]=c[i];
}
signed main()
{
	n=read();q=o=read();
	k=min(25ll,n);
	for(int i=1;i<=n;i++)
		v[i]=read();
	a[++m]=0;
	for(int i=1;i<=k;i++)
	{
		for(int j=1;j<=m;j++)
			b[j]=a[j]+v[i];
		merge(a,b,m,m);
	}
	for(int i=1;i<=q;i++)
	{
		int l=read()-1,r=read();
		s[2*i-1]=node(l,i,K2);
		s[2*i]=node(r,i,0);
	}
	q=q<<1;
	sort(s+1,s+1+q);
	for(int i=1;i<=q;i++)
		p[i]=s[i].x+K*s[i].id+s[i].fl;
	for(int i=k+1;i<=n;i++)
	{
		int t=0;
		for(int j=1;j<=q;j++)
			if((p[j]%K)-v[i]>=0)
				b[++t]=p[j]-v[i];
		merge(p,b,q,t);
	}
	for(int i=1,j=1;i<=q;i++)
	{
		while(j<=m && (p[i]%K)>=a[j]) j++;
		int id=(p[i]%K2)/K,tg=p[i]/K2;
		if(tg) ans[id]-=(j-1);
		else ans[id]+=(j-1);
	}
	for(int i=1;i<=o;i++)
		printf("%lld\n",ans[i]);
}
上一篇:SQL:空值null判断和操作


下一篇:数据库学习(二)