[ARC150F] Constant Sum Subsequence

[ARC150F] Constant Sum Subsequence

更好的阅读体验

[ARC150F] Constant Sum Subsequence

很有意思的题。

nexi,j 表示位置 i 后面的最小的满足 k>iak=jk,则问题可以抽象为:

fi=maxj=1inexfij,j

直接做是 O(S2logS) 的。这个东西也不像是用线段树之类的东西可以优化的,打表发现也没有决策单调性,考虑从问题本身入手。

关键性质:f 严格单调递增。证明很简单,可以在 fi1 对应的子序列后面加一个 1,所以 fi>fi1

考虑用类似 CDQ 分治的思路,分治计算 f。假设当前计算 区间 [l,r],先计算左半边 [l,l+r2],然后考虑左对右的贡献,然后计算右半边 [l+r2+1,r]

因为 f 是单调递增的,所以 i[l+r2+1,r],fi>fmid。考虑对于每一个 j,左半边的 nex 应当是这样的:

1.PNG

其中上下位置代表 [l,r],小方格的左右位置代表 fi,向右的线表示 nexfi,j。注意到左上角的两个 f 一定没有贡献,有贡献的一定是最右边的一段区间,这时候可以 seg beats 直接做了,但是其实还是没有必要。因为 f 严格单增,所以我们只需要考虑第三个小方格的贡献即满足 nexfi,j=nexfmid,j 的最小的 i,因为用 fi 去更新 fi+j 之后不可能用 fi+1 去更新 fi+j+1,因为两者的 nex 是一样的。所以只需要枚举每一个 j,找到满足要求的最小的 i 去更新右半部分的数组即可,需要注意边界问题。复杂度 O(SlogSlogn),代码并不难写。

注意观察性质可以使问题得到很大的简化。其中分治的本质是找到一个合适的分界线来寻找最优决策点。

	int n,m,a[1500010],lst[200010],pr[1500010],f[200010];
	vector<int> ve[200010];
	inline int nex(int i,int j)
	{
		auto it=upper_bound(ve[j].begin(),ve[j].end(),(i-1)%n+1);
		if(it==ve[j].end())return ve[j].front()+((i-1)/n+1)*n;
		return *it+(i-1)/n*n;
	}
	int find(int L,int R,int x)
	{
		int mid;
		while(L<R)
		{
			mid=L+((R-L)>>1);
			if(f[mid]>=x)R=mid;
			else L=mid+1;
		}
		return L;
	}
	void solve(int l,int r)
	{
		if(l==r)return;
		int mid=l+((r-l)>>1),pos,pre;
		solve(l,mid);
		for(int i=1;i<=r-l;++i)
		{
			pos=nex(f[mid],i),pre=(pos-1)/n*n+pr[(pos-1)%n+1];
			pre=find(l,mid,pre);
			if(pre+i>r)continue;
			pre=max(pre,mid+1-i);
			assert(pre+i>mid);
			assert(pre+i<=r);
			assert(nex(f[pre],i)==pos);
			assert(pre==l||nex(f[pre-1],i)!=pos);
			f[pre+i]=max(f[pre+i],pos);
		}
		solve(mid+1,r);
	}
	inline void mian()
	{
		read(n,m);
		for(int i=1;i<=n;++i)read(a[i]),ve[a[i]].eb(i);
		for(int i=1;i<=n;++i)lst[a[i]]=i-n;
		for(int i=1;i<=n;++i)pr[i]=lst[a[i]],lst[a[i]]=i;
		solve(0,m),write(f[m]);
	}
posted @   WrongAnswer_90  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通

This blog has running: 555 days 20 hours 30 minutes 11 seconds

点击右上角即可分享
微信分享提示