首页 > 其他分享 >20AB-day3 Good Subsegments

20AB-day3 Good Subsegments

时间:2024-10-10 20:49:18浏览次数:9  
标签:rt Good return int s2 s1 Subsegments day3 key

20AB-day3 Good Subsegments

题意

给你一个长度为 \(n\) 的序列 \(a\),问有多少个子区间,满足 \(\sum_{i=l}^r 2^{a_i}=2^x\),其中 \(x\) 为非负整数。

原题解

第一个想法:若 \(2^{a_l}+2^{a_{l + 1}}+\cdots +2^{a_r}=2^x\),则 \(x\le \max(a_l,a_{l + 1},\cdots,a_r)+\log n\)。

第二个想法:为检验 \(2^{a_l}+2^{a_{l + 1}}+\cdots +2^{a_r}=2^x\),可使用若干随机素数 \(p\) 并检验 \(2^x\bmod p\) 是否等于下面的和对 \(p\) 取模所得结果。

第三个想法:可使用分治算法,假设最大值在右侧,对于固定的 \(r\),存在 \(l\) 的某个后缀,其中最大值等于 \(\max(a_m,a_{m + 1},\cdots,a_r)\)。可确定 \(x\)(仅有 \(\log\) 种可能),然后需检验在给定后缀上是否存在模 \(p\)(对于若干不同的 \(p\))的所需和。使用哈希表可在 \(O (1)\) 时间内进行检验。

总复杂度为 \(O (n\log^2 n)\)。

思路

首先有原题解的结论:若 \(2^{a_l}+2^{a_{l + 1}}+\cdots +2^{a_r}=2^x\),则 \(x\le \max(a_l,a_{l + 1}, \cdots,a_r) + \log n\)。

一个想法是预处理前缀和,然后对于每个 \(l\),枚举 \(x\),计算有多少个 \(r\) 满足 \(s_l+2^x=s^r\)。

因为前缀和不好记录,我们可以考虑哈希来判断,判断是 \(O(1)\)。

不喜欢题解的分治做法,感觉笛卡尔树启发式合并的做法更加优美。

对于一个区间最大值,考虑把它的左边或者右边插入哈希表,然后枚举没有插入哈希表的一边,然后枚举每一个 \(x\),然后在哈希表查询满足等式的点的数量。

但是笛卡尔树最坏深度是 \(O(n)\),因此考虑启发式合并,每次合并大的儿子的哈希表,删除小儿子的哈希表,然后枚举小儿子的结点。有一些加减 \(1\) 的细节很讨厌。

时间复杂度是 \(O(n \log^2 n)\) 的。要手写哈希表qwq。

怎么还要卡常?

过哩!其实题目不用卡常,是我复杂度写假了,快速幂多叠了一个 log

code

感觉有点难写。

#include<bits/stdc++.h>
#define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
const int N=2e5+7;
#define isdigit(x) (x>='0'&&x<='9')
template <typename T >
inline void read(T & x) {
	x=0;
	T fl=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') fl=-1;
	for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
	x=x*fl;
}
int n;
int a[N];
ll ans;
const int mod1=1e9+103,mod2=1e9+123;
typedef pair<int,int> pii;
#define fi first
#define se second
pii ksm(ll a,ll b) {
	ll s1=1,s2=1;
	ll a1=a,a2=a;
	while(b) {
		if(b&1) s1=s1*a1%mod1,s2=s2*a2%mod2;
		a1=a1*a1%mod1;a2=a2*a2%mod2;
		b>>=1;
	}
	return {s1,s2};
}
int add1(int a,int b) { return a+b>=mod1?a+b-mod1:a+b; }
int add2(int a,int b) { return a+b>=mod2?a+b-mod2:a+b; }
int s1[N][20],s2[N][20]; 
const int sz=1e7+103;
struct _hash{
	int head[sz];
	int f(pii key) {
		return (key.fi+key.se)%sz;
	}
	struct _map {
		pii val;
		int key;
		int num;
		int ne;
	}mp[N];
	int cnt;
	void clear() {
		while(cnt) head[mp[cnt--].key]=0;
	}
	int find(pii key) {
		int h=f(key);
		for(int i=head[h];i;i=mp[i].ne) if(mp[i].val==key) return i;
		return 0; 
	}
	void insert(pii key) {
		int h=f(key);
		int it=find(key);
		if(it) mp[it].num++;
		else mp[++cnt]={key,h,1,head[h]},head[h]=cnt;
	}
	int operator [] (int it) const { return mp[it].num; }
}hashmp;
int st[N][20];
int _max(int x,int y) { return a[x]>a[y] ? x : y; }
int getmax(int l, int r) { 
	int lg=__lg(r-l+1);
	return _max(st[l][lg],st[r-(1<<lg)+1][lg]);
}
const int lgg=20;
void solve(int l, int r) {
	if(l>r) {
		hashmp.insert({s1[l-1][0],s2[l-1][0]});
		return;
	}
	int rt=getmax(l,r);
	if(rt-l>r-rt) {
		solve(rt+1,r);
		hashmp.clear();
		solve(l,rt-1);
		rep(i,rt,r) {
			rep(x,a[rt],a[rt]+lgg-1) {
				auto ss=ksm(2,x);
				pii key={add1(mod1-ss.fi,s1[i][0]),add2(mod2-ss.se,s2[i][0])};
				int it=hashmp.find(key);
				if(it) ans+=hashmp[it];
			}
		}
		rep(i,rt,r) hashmp.insert({s1[i][0],s2[i][0]});
	}else {
		solve(l,rt-1);
		hashmp.clear();
		solve(rt+1,r);
		rep(i,l-1,rt-1) {
			rep(x,a[rt],a[rt]+lgg-1) {
				auto ss=ksm(2,x);
				pii key={add1(ss.fi,s1[i][0]),add2(ss.se,s2[i][0])};
				int it=hashmp.find(key);
				if(it) ans+=hashmp[it];
			}
		}
		rep(i,l-1,rt-1) hashmp.insert({s1[i][0],s2[i][0]});
	}
}
int main() {
	#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("my4.out","w",stdout);
	#endif
	read(n);
	rep(i,1,n) {
		st[i][0]=i;
		read(a[i]);
		pii x=ksm(2,a[i]);
		s1[i][0]=add1(s1[i-1][0],x.fi);
		s2[i][0]=add2(s2[i-1][0],x.se);
		rep(k,1,lgg-1) s1[i][k]=add1(s1[i][k-1],s1[i][k-1]),s2[i][k]=add2(s2[i][k-1],s2[i][k-1]);
	}
	int lg=__lg(n+1);
	rep(k,1,lg) {
		for(int i=0;i+(1<<k)-1<=n;i++) {
			st[i][k]=_max(st[i][k-1],st[i+(1<<(k-1))][k-1]);
		}
	}
	solve(1,n);
	pf("%lld\n",ans);
}

标签:rt,Good,return,int,s2,s1,Subsegments,day3,key
From: https://www.cnblogs.com/liyixin0514/p/18456300

相关文章

  • Day3 备战CCF-CSP练习
    Day3题目描述目前在一个很大的平面房间里有\(n\)个无线路由器,每个无线路由器都固定在某个点上。任何两个无线路由器只要距离不超过\(r\)就能互相建立网络连接。除此以外,另有\(m\)个可以摆放无线路由器的位置。你可以在这些位置中选择至多\(k\)个增设新的路由器。你的......
  • leetcode 刷题day35动态规划Part04 背包问题(1049. 最后一块石头的重量 II 、494. 目标
    1049.最后一块石头的重量II思路:解题的难度在于如何转化为背包问题。本题的核心思路是让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题,和416.分割等和子集非常像了。首先,背包的容量target为sum/2向下取整,得到dp[target]就是分出来较小的一堆,用su......
  • leetcode 刷题day37动态规划Part06背包问题( 322. 零钱兑换、279.完全平方数、139.单词
    322.零钱兑换思路:每种硬币的数量是无限的,是典型的完全背包问题。但是题目要求等于目标值的最小硬币个数。所以这里需要对动规五部曲进行分析。动规五部曲:1、确定dp数组以及下标的含义dp[j]:凑足总额为j所需钱币的最少个数为dp[j]2、确定递推公式凑足总额为j-coins[i......
  • 代码随想录算法训练营day3|● 203.移除链表元素 ● 707.设计链表 ● 206.反转链表
    学习资料:https://programmercarl.com/链表理论基础.html#链表的类型可设置虚拟头结点dummy_head链表最后指向Null一个节点包含值和索引学习记录:203.移除链表元素(基本ListNode(),cur.next,cur.next.val)点击查看代码#Definitionforsingly-linkedlist.#classListNod......
  • 【牛客训练记录】2024牛客国庆集训派对day3
    赛后反思还是只开出来一题TATH题构造一个01矩阵,想要横竖斜三个数都不同,好像方法有很多,我们考虑交错着放010101011010101001010101上面这种长度为\(1\)的01显然不行,因为斜着也算,所以我们考虑构造长度为\(2\)的01,例如00111100这样001100111100110000110011110......
  • DAY3-补题
    一题之计在于补呐补题很快乐的一点就是看不懂且听不明白但是写注释中理解到了。果然学会一道题最简单的方式是给一个纯萌新讲。说在前面今天%你赛手感非常好,可能是换了一个位置的原因(玄首先T1没有读错题是一个比较大的进步,因为DAY1和2都是因为差不多这个原因寄掉了,读对题目果......
  • 题解:CF724E Goods transportation
    可以在cnblog中阅读。题意有\(n\)座城市,第\(i\)座城市生产了\(p_i\)件货物,最多可以出售\(s_i\)件货物,编号小的城市可以向编号大的城市运输至多\(c\)件货物,问最多能出售多少货物。\(n\le10^4\)。分析乍一看是一个网络流问题,可以这样建图,令\(S\)为源点\(T\)......
  • 题解:SP7973 ACPC10E - Sometimes, a penalty is good!
    比较简单的一道数学题。思路:计算小组赛的比赛总数。longlongstage1=G*T*(T-1)/2;每组有\(T\)个队伍,每个队伍都需要与其他\(T-1\)个队伍比赛,共有\(T\cdot(T-1)\)场比赛。共有\(G\)组,因此小组赛总比赛数为\(\frac{G\cdotT\cdot(T-1)}{2}\)。计算进入......
  • CF1214G Feeling Good 题解
    题目链接点击打开链接题目解法我真菜啊,感觉每一步都不难,但一步都没想到/yun考虑两行\(x,y\)什么时候可以构造出合法的矩形?即\(x\)中需要有\(y\)对应位置为\(0\)的\(1\),\(y\)中需要有\(x\)对应位置为\(0\)的\(1\)归纳一下,\(x\)不是\(y\)的子集且\(y\)不......
  • leetcode刷题day34|动态规划Part03 背包问题(01背包问题 二维、01背包问题 一维、416.
    0-1背包问题二维动规五部曲1、确定dp数组以及下标的含义dp[i][j]表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。(取物品时可以是取0-i的任意一个,或者是他们的组合)2、确定递推公式不放物品i:背包容量为j,里面不放物品i的最大价值是dp[i-1][j]......