[传智杯 #5 初赛] I-不散的宴会

2023-10-22 22:12
文章标签 初赛 传智杯 不散 宴会

本文主要是介绍[传智杯 #5 初赛] I-不散的宴会,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

洛谷P8877 [传智杯 #5 初赛] I-不散的宴会

题目大意

学生社会可以被看作一个排列成等腰直角三角形的节点阵列。该节点阵列共有 n n n行,第 i i i行共有 i i i个节点,我们将第 i i i行第 j j j列的节点标号为 ( i , j ) (i,j) (i,j)

这些点具有权值。节点 ( i , j ) (i,j) (i,j)的权值为 r i ⊕ c j r_i\oplus c_j ricj,其中 r r r c c c是给定的 01 01 01序列。

这些点有边相连。对于 1 ≤ i < n 1\leq i<n 1i<n 1 ≤ j < i 1\leq j<i 1j<i,会有一条边连接 ( i , j ) (i,j) (i,j) ( i + 1 , j ) (i+1,j) (i+1,j)。此外,对于 2 ≤ i ≤ n 2\leq i\leq n 2in,还会有边连接 ( i , i ) (i,i) (i,i) ( i − 1 , a i ) (i-1,a_i) (i1,ai),其中 a a a是给定的序列。

现在你需要从这些节点中,选出一些节点,使得这些节点间两两不存在边相连,最大化选出来的节点的权值之和。

1 ≤ n ≤ 1 0 6 , 1 ≤ a i < i 1\leq n\leq 10^6,1\leq a_i<i 1n106,1ai<i


题解

首先,我们可以发现,这个图有 n ( n + 1 ) 2 \dfrac{n(n+1)}{2} 2n(n+1)个点, n ( n − 1 ) 2 + ( n − 1 ) \dfrac{n(n-1)}{2}+(n-1) 2n(n1)+(n1)条边,边数比点数少 1 1 1,这个图还是连通的,所以这个图是一棵树。

我们将所有第 1 1 1层的点、第 n n n层的点和度数为 3 3 3的点设为关键点。那么关键点的个数是 O ( n ) O(n) O(n)的,因为关键点只可能出现在第 1 1 1层、第 n n n层和连接 ( i , i ) (i,i) (i,i) ( i − 1 , a i ) (i-1,a_i) (i1,ai)的边上(可以自己画图感受一下)。

除了关键点,其他点的度数都为 2 2 2,那么这些点肯定都在一条链上。于是,我们可以把一条链看成两个关键点的边,这些关键点和边就构成一棵虚树,因为它的点的个数是 O ( n ) O(n) O(n)的,所以边的个数也是 O ( n ) O(n) O(n)的。

建虚树时,我们从下往上枚举每一行,用 v i v_i vi表示第 i i i列最后一个关键点在虚树上的编号。假设当前遍历到第 i i i行,则将 ( i − 1 , a i ) (i-1,a_i) (i1,ai) v a i v_{a_i} vai在虚树上连一条边,将 ( i , i ) (i,i) (i,i) ( i − 1 , a i ) (i-1,a_i) (i1,ai)在虚树上连一条边,并用 ( i − 1 , a i ) (i-1,a_i) (i1,ai)来更新 v a i v_{a_i} vai,还要求出新加在虚树上的点的权值。

建好的虚树后,即求树上最大点权独立集,可以用 D P DP DP来求。

f u , g u f_u,g_u fu,gu分别表示选择或不选择虚树上的节点 u u u的情况下,子树 u u u能取得的最大点权独立集的值。

假设有两个关键点 u u u v v v,它们之间通过链 s = { v 1 , v 2 , … , v k } s=\{v_1,v_2,\dots,v_k\} s={v1,v2,,vk}连接,则转移式为

f u + = max ⁡ { v a l ( v 2 , v 3 , … , v k − 1 ) + f v , v a l ( v 2 , v 3 , … , v k ) + g v } f_u+=\max\{val(v_2,v_3,\dots,v_{k-1})+f_v,val(v_2,v_3,\dots,v_k)+g_v\} fu+=max{val(v2,v3,,vk1)+fv,val(v2,v3,,vk)+gv}

g u + = max ⁡ { v a l ( v 1 , v 2 , … , v k − 1 ) + f v , v a l ( v 1 , v 2 , … , v k ) + g v } g_u+=\max\{val(v_1,v_2,\dots,v_{k-1})+f_v,val(v_1,v_2,\dots,v_k)+g_v\} gu+=max{val(v1,v2,,vk1)+fv,val(v1,v2,,vk)+gv}

其中 v a l ( v 1 , v 2 , … , v k ) val(v_1,v_2,\dots,v_k) val(v1,v2,,vk)表示 v 1 v_1 v1 v k v_k vk在不能选择相邻元素的情况下可以取得的最大点权独立集。

这个图还有一个性质:虚树中每条边在原图中对应的链上的点在同一列上。

那么,假设这条链在第 k k k列,其所在的区间为 [ a , b ] [a,b] [a,b],则:

  • c k = 0 c_k=0 ck=0,则每个位置的权值为 r a , r a + 1 … , r b r_a,r_{a+1}\dots,r_b ra,ra+1,rb
  • c k = 1 c_k=1 ck=1,则每个位置的权值为 ¬ r a , ¬ r a + 1 , … , ¬ r b \neg r_a,\neg r_{a+1},\dots,\neg r_b ¬ra,¬ra+1,,¬rb

那么,问题就转化为,查询对 r r r序列或 ¬ r \neg r ¬r序列求区间最大点独立集的大小。

对于一个 01 01 01序列,我们可以用贪心来求最大点独立集。比如,对于长度为 2 k 2k 2k的全 1 1 1段,最大点独立集显然为 k k k;对于长度为 2 k + 1 2k+1 2k+1的全 1 1 1段,最大点独立集显然为 k + 1 k+1 k+1。对于含有 0 0 0的序列,可以以 0 0 0作为分隔划分出各种全 1 1 1段,在分别求和相加即可。

下面,我们考虑如何求区间最大点独立集。

我们可以预处理出两个数组:

  • h i h_i hi表示仅考虑前 i i i个元素得出的最大点独立集的大小
  • p i p_i pi表示第 i i i个元素所在的全 1 1 1段的最后一个 1 1 1的位置。如果位置 i i i 0 0 0,则 p i = i − 1 p_i=i-1 pi=i1

假设我们当前要计算区间 [ l , r ] [l,r] [l,r]的最大点权独立集的大小,那么结果为

h r − h min ⁡ ( r , p l ) + ⌊ min ⁡ ( r , p l ) − l + 2 2 ⌋ h_r-h_{\min(r,p_l)}+\lfloor\dfrac{\min(r,p_l)-l+2}{2}\rfloor hrhmin(r,pl)+2min(r,pl)l+2

即先求出 [ min ⁡ ( r , p l ) + 1 , r ] [\min(r,p_l)+1,r] [min(r,pl)+1,r]这一段的最大点权独立集的大小,再统计 [ l , min ⁡ ( r , p l ) ] [l,\min(r,p_l)] [l,min(r,pl)]这一段长度为 r − min ⁡ ( r , p l ) + 1 r-\min(r,p_l)+1 rmin(r,pl)+1的全 1 1 1段的最大点权独立集大小(长度为 k k k的全 1 1 1段的最大点权独立集的大小为 ⌊ k + 1 2 ⌋ \lfloor\dfrac{k+1}{2}\rfloor 2k+1)。

时间复杂度为 O ( n ) O(n) O(n)

code

#include<bits/stdc++.h>
using namespace std;
const int N=1000000;
int n,cnt=0,R[N+5],C[N+5],a[N+5],v[N+5],vd[N+5],s[2*N+5],h[2][N+5],p[2][N+5];
int tot=0,d[2*N+5],l[2*N+5],r[2*N+5];
long long f[2*N+5],g[2*N+5],w[2*N+5][4];
long long gt(int i,int l,int r){if(r-l+1<=-2) return -1e18;if(l>r) return 0ll;int e=C[i];return 1ll*h[e][r]-h[e][min(r,p[e][l])]+(min(r,p[e][l])-l+2)/2;
}
void gtin(long long *v1,int i,int l,int r){v1[0]=gt(i,l,r);v1[1]=gt(i,l,r-1);v1[2]=gt(i,l+1,r);v1[3]=gt(i,l+1,r-1);
}
void add(int xx,int yy,int i,int ll,int rr){l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;gtin(w[tot],i,ll,rr);
}
void init(int e){for(int i=1,lst=0;i<=n;i++){if((R[i]^e)==0){h[e][i]=h[e][i-1];lst=i;}else h[e][i]=h[e][lst]+(i-lst+1)/2;}p[e][n+1]=n;for(int i=n;i>=1;i--){if((R[i]^e)==0) p[e][i]=i-1;else p[e][i]=p[e][i+1];}
}
void dfs(int u){f[u]=s[u];for(int i=r[u];i;i=l[i]){int v=d[i];dfs(v);f[u]+=max(f[v]+w[i][3],g[v]+w[i][2]);g[u]+=max(f[v]+w[i][1],g[v]+w[i][0]);}
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&R[i]);for(int i=1;i<=n;i++) scanf("%d",&C[i]);for(int i=2;i<=n;i++) scanf("%d",&a[i]);init(0);init(1);for(int i=1;i<=n;i++){v[i]=++cnt;vd[i]=n;s[cnt]=R[n]^C[i];}for(int i=n;i>=2;i--){add(++cnt,v[a[i]],a[i],i,vd[a[i]]-1);v[a[i]]=cnt;vd[a[i]]=i-1;s[cnt]=R[i-1]^C[a[i]];add(cnt,v[i],i,i,vd[i]-1);}dfs(cnt);printf("%lld",max(f[cnt],g[cnt]));return 0;
}

这篇关于[传智杯 #5 初赛] I-不散的宴会的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/263929

相关文章

百度之星 2015 初赛(1) 1002 找连续数

找连续数      Accepts: 401      Submissions: 1911  Time Limit: 2000/1000 MS (Java/Others)      Memory Limit: 32768/32768 K (Java/Others) Problem Description 小度熊拿到了一个无序的数组,对于这个数组,小度熊想知道是

百度之星初赛1002(二分搜索)

序列变换    Accepts: 816    Submissions: 3578  Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description 给定序列 A={A1,A2,...,An} , 要求改变序列A中

百度之星初赛1006(计算几何:能包含凸包的最小矩形面积)

矩形面积    Accepts: 717    Submissions: 1619  Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description 小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些

信息学奥赛初赛天天练-83-NOIP2014普及组-基础题2-输入设备、输出设备、操作系统、二进制、整数除法、while、do while循环

1 NOIP 2014 普及组 基础题2 4 以下哪一种设备属于输出设备( ) A 扫描仪 B 键盘 C 鼠标 D 打印机 5 下列对操作系统功能的描述最为完整的是( ) A 负责外设与主机之间的信息交换 B 负责诊断机器的故障 C 控制和管理计算机系统的各种硬件和软件资源的使用 D 将没有程序编译成目标程序 11 下列各无符号十进制整数中,能用八位二进制表示的数中最大的是( ) A 296

CSP初赛知识点讲解(十二)

图 简单来说:用边把一些点连接起来叫图 有向图:边有方向的图,比如边a–>b,只能由a到b,不 能由b到a。 无向图:边没有方向的图,连接点a和b,那么a和b可以相互到达。 结点的度:无向图中与结点相连的边的数目。 结点的入度:在有向图中,以这个结点为终点的有向边 的数目。 结点的出度:在有向图中,以这个结点为起点的有向边 的数目。 联通图:图中任意两点能互相到达的图。 完全图:一

P7492 [传智杯 #3 决赛] 序列

*原题链接* 一道类似势能线段树的题,区间按位或上k,不满足区间可合并的性质,只能暴力的单点修改。 但是考虑按位或的性质,一个数或上另一个数,只会变大或不变,如果我们能找到一个方法,能够判定区间里的数,或上k后是否有改变,就可以避免的暴力了。我一开始想的是线段树里维护一个的数组,表示区间内所有数的二进制表示下某一位是否为1,但这太难写,最后无奈去看官方题解,发现只要维护区间所有数的按位与和An

2024年“羊城杯”粤港澳大湾区网络安全大赛 初赛 Web数据安全AI 题解WriteUp

文章首发于【先知社区】:https://xz.aliyun.com/t/15442 Lyrics For You 题目描述:I have wrote some lyrics for you… 开题。 看一下前端源码,猜测有路径穿越漏洞 http://139.155.126.78:35502/lyrics?lyrics=../../../../../etc/passwd 简单看

NOIP 2015 CCF (CSP -J)初赛真题

第二十 一届全国青少年信息学奥林匹克联赛初赛 ; 普及组C++ 语言试题 竞 赛 时 间: 20 1 5 年 1 0 月 1 1 日 1 4 : 3 0~ 1 6 : 3 0 选 手注 意: • 试腰紙共有7 页,答題紙共有2页,满分100 分。请在答感統上炸答,写在試感纸上的一律无 效。 • 不得使用任何电子设 备(如计算器、手机、 电子词典等》或查阅 任何书籍發 料。 一、单项选择题(

信息学奥赛初赛天天练-80-NOIP2015普及组-基础题5-错位排列、二叉树、完全二叉树、叶子节点、完全二叉树叶子节点

NOIP 2015 普及组 基础题5 21 重新排列 1234使得每一个数字都不在原来的位置上,一共有( )种排法 22 一棵结点数为 2015的二叉树最多有( )个叶子结点 2 相关知识点 1) 错位排列 考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n) 错排问题最早被尼古拉·伯努利和欧拉研究

信息学奥赛初赛天天练-79-NOIP2015普及组-基础题4-即时通讯软件、二叉树遍历、前序遍历、中序遍历、后序遍历、算法时间复杂度

NOIP 2015 普及组 基础题4 11 下面哪种软件不属于即时通信软件( ) A QQ B MSN C 微信 D P2P 16 前序遍历序列与中序遍历序列相同的二叉树为( ) A 根结点无左子树 B 根结点无右子树 C 只有根结点的二叉树或非叶子结点只有左子树的二叉树 D 只有根结点的二叉树或非叶子结点只有右子树的二叉树 18 下列选项中不属于视频文件格式的是( ) A TXT B AV