首页 > 其他分享 >2024 提高组杂题

2024 提高组杂题

时间:2024-11-24 22:12:38浏览次数:11  
标签:线段 int 提高 times 2024 组杂题 MAXN 操作 sum

2024 提高组杂题

T1 [CF1763C] Another Array Problem

弱智题。容易发现无论怎么操作 \(\sum a_i\) 不会超过 \(\max a_i\times n\),且在 \(n\ge4\) 时一定能够取到。所以我们只需考虑 \(n=2\) 或 \(n=3\) 的情况。

\(n=2\) 时,只需取 \(\max(a_1+a_2,2\times|a_1-a_2|)\) 即可。

\(n=3\) 时,数组最后的取值只可能有 \(a_1+a_2+a_3,3\times a_1,3\times a_3,3\times|a_1-a_2|,3\times|a_2-a_3|\) 五种情况。取 \(\max\) 即可。

constexpr int MAXN=2e5+5;
int T,n;
long long a[MAXN];

int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;++i) a[i]=read();
		if(n==2) write(max(abs(a[2]-a[1])<<1,a[1]+a[2]));
		else if(n==3) write(max(a[1]+a[2]+a[3],max({a[1],a[3],abs(a[1]-a[2]),abs(a[2]-a[3])})*n));
		else write(*max_element(a+1,a+n+1)*n);
	}
	return fw,0;
}

T2 [CF1775E] The Human Equation

精妙构造题。题目所给的操作看似复杂,但观察到一个加一、一个减一这种操作很像差分,于是把 \(a\) 数组当成差分数组,还原出原数组 \(b\)。则在 \(a\) 数组上的每一次操作都可以转化为将 \(b\) 数组的任意值加或减一个数

显然最少操作次数为 \(b\) 数组的极差。

constexpr int MAXN=2e5+5;
int T,n;
long long a[MAXN];

int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;++i) a[i]=a[i-1]+read();
		long long mx=0,mn=0;
		for(int i=1;i<=n;++i) mx=max(mx,a[i]),mn=min(mn,a[i]);
		write(mx-mn);
	}
	return fw,0;
}

T3 [CF1290C] Prefix Enlightenment

前置知识:种类并查集。代表例题:[NOI2001] 食物链

首先需要理解 ”任意三个子集的交集为空集“ 是什么意思。翻译成人话就是:任意一点顶多出现在两个集合中。于是我们设 \(L_i,R_i\) 分别为包含 \(i\) 点的两个集合(若没有则为 \(0\))。

题目要求求出对于所有 \(m_i\),于是我们考虑一个个加入。对于每个点都有如下情况讨论:

  • \(S_i=0\),则 \(L_i,R_i\) 能且仅能操作一个;
  • \(S_i=1\),则 \(L_i,R_i\) 要么都操作,要么都不操作。

这种维护条件的连通性的题目,想到种类并查集。对于每个集合 \(k\),设立两个点分别表示操作/不操作,记为 \(p(k,0/1)\)。则对于如上条件,我们只需连边:

  • \(S_i=0\),则连边 \(p(L_i,0)\leftrightarrow p(R_i,0)\) 和 \(p(L_i,1)\leftrightarrow p(R_i,1)\);
  • \(S_i=1\),则连边 \(p(L_i,0)\leftrightarrow p(R_i,1)\) 和 \(p(L_i,1)\leftrightarrow p(R_i,0)\)。

显然,每一条边都代表一种合法的方案。连完边之后,对于每一个连通块,要么选 ”操作“,要么选 ”不操作“,于是我们在合并的时候统计第一层和第二层的最小值即可。

需要注意:

  1. 注意不能按秩合并,那样会导致关系混乱;只能用路径压缩。
  2. 还要注意:要处理一个点仅被一个集合包含的情况。在上文我们已经说了,如果不存在就是 \(0\)。所以 \(0\) 点需要用来处理这种情况。并查集的空间应该是 \(O(2n)\) 的。
  3. 对于这个 \(0\) 点不能操作。所以对于 \(0\) 点的两层情况需要特判,只能取不包含的那一部分。
#include<bits/stdc++.h>
using namespace std;

constexpr int MAXN=3e5+5;
int n,k,ans;
char s[MAXN];
int L[MAXN],R[MAXN];
int f[MAXN<<1],siz[MAXN<<1][2];
int find(int x){
	return f[x]==x?x:f[x]=find(f[x]);
}
void combine(int u,int v){
	int fu=find(u),fv=find(v);
	if(fu==fv) return;
	ans-=min(siz[fu][0],siz[fu][1])+min(siz[fv][0],siz[fv][1]);
	siz[fu][0]+=siz[fv][0];
	siz[fu][1]+=siz[fv][1];
	f[fv]=fu;
	ans+=min(siz[fu][0],siz[fu][1]);
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>k>>(s+1);
	for(int i=1,c,x;i<=k;++i){
		cin>>c;
		for(int j=1;j<=c;++j){
			cin>>x;
			L[x]?R[x]=i:L[x]=i;
		}
	}
	for(int i=0;i<=k;++i) f[i]=i,siz[i][0]=1;
	for(int i=k+1;i<=(k<<1|1);++i) f[i]=i,siz[i][1]=1;
	for(int i=1,rt;i<=n;++i){
		if(s[i]=='1') combine(L[i],R[i]),combine(L[i]+k+1,R[i]+k+1);
		else combine(L[i]+k+1,R[i]),combine(L[i],R[i]+k+1);
		rt=find(0);
		if(siz[rt][0]<siz[rt][1]) cout<<(ans>>1)+siz[rt][1]-siz[rt][0]<<'\n';
		else cout<<(ans>>1)<<'\n';
	}
	return 0;
}

T4 [CF1458D] Flip and Reverse

想象力/人类智慧/脑电波的构造题。对原串记 \(0\) 为 \(-1\),\(1\) 为 \(+1\),得到新的序列;对这个序列做前缀和,记前缀和序列为 \(s\),并连一条 \(s_i\to s_{i+1}\) 的有向边,可以得到一张图,一个欧拉回路就对应一个字符串。

然后转化题目中的奇怪操作。

  1. 要求 \([l,r]\) 的 01 个数相等,则 \(s_{l-1}=s_r\);
  2. 翻转 + 反转,实际上等于将 \([l,r]\) 的这些边反向。

所以该操作就等价于选择一个环然后将环上所有边反向

然后需要观察出一个性质:操作前后,原图包含的边集不变。因为操作的是一个环,在操作前 \(x\to y\) 和 \(y\to x\) 的数量是相同的,所以操作后也是相同的。

还需要观察出另外一个性质。。原图任意一条欧拉回路代表的字符串都可以由原串经过操作得到。具体可以看 @tzc_wk 的证明

于是此题就变为:求字典序最小的欧拉序!

直接贪心即可。

#include<bits/stdc++.h>
using namespace std;

constexpr int MAXN=5e5+5,N=5e5;
int T,n,cnt[MAXN<<1][2];
string s;

int main(){
	ios::sync_with_stdio(0);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>T;
	while(T--){
		cin>>s;
		n=s.size();
		s=' '+s;
		for(int i=1,cur=0;i<=n;++i){
			++cnt[cur+N][s[i]-'0'];
			cur+=s[i]=='0'?-1:1;
		}
		for(int i=1,x=0;i<=n;++i)
			if(cnt[x+N][0]&&cnt[x-1+N][1])
				--cnt[x+N][0],--x,cout<<0;
			else if(cnt[x+N][1])
				--cnt[x+N][1],++x,cout<<1;
			else --cnt[x+N][0],--x,cout<<0;
		cout<<'\n';
	}
	return 0;
}

T5 [CF1389F] Bicolored Segments

线段树优化 DP,当然也可以用神秘的 multiset 做。

首先像我就想到二分答案 + 离散化上去了,不过想一想就知道会假。

不过离散化肯定是正确的,先把所有区间离散化。

正解设 \(f_{i,j,0/1}\) 表示考虑到前 \(i\) 个区间、最后一个放入的区间的右端点是 \(j\)、最后放入的区间的颜色是 \(0/1\)。其中第一维可以滚掉,第二维离散化之后空间不成问题。考虑优化时间。

不妨设当前线段是黑色的,也就是 \(1\)。

如果不选当前线段,显然有:\(f_{i,r_i,1}=f_{i-1,r_{i-1},1}\)。

如果选当前线段,设上一条被选择的白色线段的右端点是 \(r_j\),则所有左右端点都在 \((r_j,r_i]\) 的黑色线段都可以选择。则:\(f_{i,r_i,1}=\max\{f_{j,r_j,0}+w\}\),其中 \(w\) 为这些黑色线段数量。

这里想要优化就需要状态提前计算。事先将所有 \(r_j<l_i\) 的 \(f_{j,r_j,0}\) 都加上一个 \(1\),则方程变为 \(f_{i,r_i,1}=\max\{f_{j,r_j,0}\}\)。用一棵支持区间加、单点修、区间最大值的线段树搞它。

#include<bits/stdc++.h>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
using namespace std;

char buf[1<<20],*p1=buf,*p2=buf;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch))ch=='-'&&(f=-1),ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
constexpr int MAXN=2e5+5;
int n,mx,b[MAXN<<1],tot;
struct SEG{
	int l,r,t;
	bool operator<(const SEG&x)const{
		return r<x.r;
	}
}a[MAXN];
int max(int a,int b){
	return a>b?a:b;
}
struct{
	#define lp p<<1
	#define rp p<<1|1
	#define mid ((s+t)>>1)
	struct SegTree{
		int c,lazy;
	}st[MAXN<<3];
	void pushdown(int p){
		if(!st[p].lazy) return;
		st[lp].c+=st[p].lazy,st[lp].lazy+=st[p].lazy;
		st[rp].c+=st[p].lazy,st[rp].lazy+=st[p].lazy;
		st[p].lazy=0; 
	}
	void pushup(int p){
		st[p].c=max(st[lp].c,st[rp].c);
	}
	void mdf(int l,int r,int k,int s=0,int t=mx,int p=1){
		if(l<=s&&t<=r) return st[p].c+=k,st[p].lazy+=k,void();
		pushdown(p);
		if(l<=mid) mdf(l,r,k,s,mid,lp);
		if(mid<r) mdf(l,r,k,mid+1,t,rp);
		pushup(p);
	}
	void chg(int x,int k,int s=0,int t=mx,int p=1){
		if(s==t) return st[p].c=k,void();
		pushdown(p);
		if(x<=mid) chg(x,k,s,mid,lp);
		else chg(x,k,mid+1,t,rp);
		pushup(p);
	}
	int sum(int l,int r,int s=0,int t=mx,int p=1){
		if(l<=s&&t<=r) return st[p].c;
		pushdown(p);
		int res=0;
		if(l<=mid) res=max(res,sum(l,r,s,mid,lp));
		if(mid<r) res=max(res,sum(l,r,mid+1,t,rp));
		return res;
	}
}s[2];

int main(){
	n=read();
	for(int i=1;i<=n;++i){
		a[i]={read(),read(),read()-1};
		b[++tot]=a[i].l,b[++tot]=a[i].r;
	}
	sort(b+1,b+tot+1);
	tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;++i){
		a[i].l=lower_bound(b+1,b+tot+1,a[i].l)-b;
		a[i].r=lower_bound(b+1,b+tot+1,a[i].r)-b;
		mx=max(mx,a[i].r);
	}
	sort(a+1,a+n+1);
	for(int i=1,p;i<=n;++i){
		p=a[i].t;
		s[p].mdf(0,a[i].l-1,1);
		s[!p].chg(a[i].r,max(s[p].sum(0,a[i].l-1),s[!p].sum(0,a[i].r)));
	}
	printf("%d\n",max(s[0].st[1].c,s[1].st[1].c));
	return 0;
}

T6 [CF1580D] Subsequence

笛卡尔树的构造。将原式化为:

\[(m-1)\sum_{i=1}^ma_{b_i}-2\sum_{i=1}^m\sum_{j=i+1}^m\min\{a_{b_i},\dots,a_{b_j}\}~. \]

把所有的 \(a_i\) 放到笛卡尔树上,利用笛卡尔树的一个美妙的性质:连续区间最大值就是 LCA,将原式化为:

\[(m-1)\sum_{i=1}^ma_{b_i}-2\sum_{i=1}^m\sum_{j=i+1}^ma_{\operatorname{LCA}(i,j)}~. \]

设 \(f_{u,j}\) 表示节点 \(u\) 选择 \(j\) 个节点的最大价值,初始 \(f_{u,1}=(m-1)a_i\),然后类似树形背包地转移:

\[f_{u,i+j}=\max\{f_{u,i}+f_{v,j}-2\times i\times j\times a_u\}~. \]

constexpr int MAXN=4005;
int n,m,a[MAXN];
int ls[MAXN],rs[MAXN],stk[MAXN],top;
int f[MAXN][MAXN],tmp[MAXN],siz[MAXN];
void insert(int k,int w){
	while(top&&w<a[stk[top]]) ls[k]=stk[top--];
	if(top) rs[stk[top]]=k;
	stk[++top]=k;
}
bool vis[MAXN];
void dfs(int u);
void work(int u,int v){
	dfs(v);
	for(int i=0;i<=siz[u];++i) tmp[i]=f[u][i],f[u][i]=0;
	for(int i=0;i<=siz[u];++i)
		for(int j=0;j<=siz[v];++j)
			f[u][i+j]=max(f[u][i+j],tmp[i]+f[v][j]-2*a[u]*i*j);
	siz[u]+=siz[v];
}
void dfs(int u){
	f[u][1]=(m-1)*a[u];
	siz[u]=1;
	if(ls[u]) work(u,ls[u]);
	if(rs[u]) work(u,rs[u]);
}

signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i) insert(i,a[i]=read());
	for(int i=1;i<=n;++i) vis[ls[i]]=vis[rs[i]]=1;
	for(int i=1;i<=n;++i)
		if(!vis[i]){
			dfs(i);
			printf("%lld\n",f[i][m]);
			return 0;
		}
}

标签:线段,int,提高,times,2024,组杂题,MAXN,操作,sum
From: https://www.cnblogs.com/laoshan-plus/p/18566506

相关文章

  • 2024-2025-1 20241406刘书含 《计算机基础与程序设计》第九周学习总结
    教材学习内容总结1.指针的算术运算指针自增自减:指针变量进行自增(++)或自减(--)运算时,其地址改变量取决于它所指向的数据类型大小。以指向 int 类型(通常占4字节)的指针 p 为例,执行 p++ 后,p 的地址值会在原基础上加4字节,使其指向下一个 int 类型存储单元。同样,p-- 会让......
  • 2024 CCF BDCI 小样本条件下的自然语言至图查询语言翻译大模型微调|Google T5预训练语
    代码详见https://gitee.com/wang-qiangsy/bdci目录一.赛题介绍1.赛题背景2.赛题任务二.关于GoogleT5预训练语言模型1.T5模型主要特点2.T5模型与赛题任务的适配性分析3.模型的优化三.解题思路1.数据准备2.数据处理3.模型训练4.模型评估四.代码实现1.配置类(Config)2.数据集类(Cyp......
  • 【MX-S7】梦熊 NOIP 2024 模拟赛 3 & SMOI Round 2
    俩签到俩不可做是吧。Rank【MX-S7-T1】「SMOI-R2」HappyCard签到题一号,以为撑死评个黄但没想到那么多人不会打扑克。考虑炸弹也是三带一,出三带一肯定更优秀。考虑将所有牌变为若干个三张和剩余的,那么三张先带单张,再将对子拆开带。那么现在就有以下几种情况:单张太多,那么......
  • 2024.11.24~2024.11.28
    2024.11.24开心的周末(可能是写博客的时候比较开心吧,嘻嘻)上午刷了一套cf,在3h30min刷完了下午去打了一会乒乓球,回来时发现shr已经讲了10分钟的课了(尴尬.png)这周将扫描线,虽然说这个机房除了我以外还有不会的吗?(呃),但是起码没像讲平衡树那样一个字也听不懂的的程度了发现扫描线也没......
  • 学习日记_20241123_聚类方法(高斯混合模型)续
    前言提醒:文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。文章目录前言续:手动实现代码分析def__init__(s......
  • [20241123]PLSQL语句代码执行几次会缓存.txt
    [20241123]PLSQL语句代码执行几次会缓存.txt--//测试看看PLSQL语句代码执行几次会缓存。1.环境:SCOTT@book>@ver1PORT_STRING                   VERSION       BANNER-------------------------------------------------------------------------......
  • [20241123]测试软软解析遇到的疑惑3.txt
    [20241123]测试软软解析遇到的疑惑3.txt--//测试软软解析遇到的疑惑,就是大量软软解析以及分散执行两者的执行时间差别并不是很大,有点疑惑,发现调用select休眠的时间--//是1毫秒,而11g是1厘秒。而ash取样是1秒,这样在21c下相当于方法1000倍,11g下仅仅100倍。--//前面测试21c下的情况,在1......
  • [20241124]测试软软解析人为修改cursor pin S的mutext值.txt
    [20241124]测试软软解析人为修改cursorpinS的mutext值.txt--//测试软软解析人为修改cursorpinS的mutext值会出现怎么情况。1.环境:SCOTT@book01p>@ver2==============================PORT_STRING                  :x86_64/Linux2.4.xxVERSION    ......
  • 2024-2025-1 20241319 《计算机基础与程序设计》第九周学习总结
    作业信息这个作业属于哪个课程2024-2025-1-计算机基础与程序设计这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK09这个作业的目标操作系统责任内存与进程管理分时系统CPU调度文件、文件系统文件保护磁盘调度作业正文https://www......
  • [20241121]测试软软解析遇到的疑惑.txt
    [20241121]测试软软解析遇到的疑惑.txt--//测试软软解析遇到的疑惑,就是大量软软解析以及分散执行两者的执行时间差别并不是很大,有点疑惑,展开分析看看。1.环境:SCOTT@book01p>@ver2==============================PORT_STRING                  :x86_64/Linux......