ZROI - 2023csp七连测附加赛day1

掉大分。

A. 急急急

题目简介

给定一个长度为 的序列 ,每次操作你可以选择一个位置 ,将 折叠到 ,即:

然后删除 。需要注意的是,你选择的 必须有

问是否能够将整个序列删除到只剩下一个数时,这个数是非负整数。多测。

数据范围:

仔细发现不管怎么叠 不变,所以当 时绝无可能。然后观察样例和限制发现 时也绝无可能。

所以我们考虑无解情况只有一种,就是当某一个数 足够小(为负数)且无法被之前的所有数消掉。

对比 ,对于第二种情况,我们前面就算一个一个叠叠成一个正数也无法抵消 ,所以无解。

所以无解情况为存在一个 使得


B. 绷绷绷

题目简介

给定 个弹簧,第 个长度为 ,满足 。一共 次询问,每次询问区间

在第 时刻时,所有弹簧被松弛,会逐渐伸长。在第 时刻时,第 个弹簧在 时刻满足 时则会长度 。每次询问的 不会有任何变化。

每次询问独立,求 在第几个时刻伸长到

数据范围:

首先考虑单询问,我们记录 表示第 个位置伸长到 的时间,有递推式:

但如果存在右端点为 的相等连续段时,我们需要将其全部舍弃只保留最小,设为

然后我们拆贡献,得到:

后面这个部分显然可以用线段树维护区间最大值,然后就结束了。

时间复杂度

AC Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// ----- Eternally question-----
// Problem: B. [2023CSP七连 附加赛1] 绷绷绷
// Contest: ZROI - 23csp7连测附加赛1
// URL: http://zhengruioi.com/contest/1457/problem/2693
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// Written by: Eternity
// Time: 2023-10-04 08:23:05
// ----- Endless solution-------

#include<bits/stdc++.h>
#define re register
typedef long long ll;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1){ read(x),read(x1...); }
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<>
inline void write(bool x){ putchar(x?'1':'0'); }
template<>
inline void write(char c){ putchar(c); }
template<>
inline void write(char *s){ while(*s!='\0') putchar(*s++); }
template<>
inline void write(const char *s){ while(*s!='\0') putchar(*s++); }
template<class T,class ...T1>
inline void write(T x,T1 ...x1){ write(x),write(x1...); }
template<class T>
inline bool checkMax(T &x,T y){ return x<y?x=y,1:0; }
template<class T>
inline bool checkMin(T &x,T y){ return x>y?x=y,1:0; }
const int MAXN=2e5+10;
const int Inf=0x3f3f3f3f;
int N,Q,val[MAXN];
#define ls (p<<1)
#define rs (p<<1|1)
struct Segment
{ int l,r,val; }Tr[MAXN<<2];
inline void pushUp(int p)
{ Tr[p].val=std::max(Tr[ls].val,Tr[rs].val); }
void build(int p,int l,int r)
{
Tr[p].l=l,Tr[p].r=r;
if(l==r) return Tr[p].val=l-val[l],void();
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushUp(p);
}
int queryMax(int p,int l,int r)
{
if(l<=Tr[p].l&&Tr[p].r<=r) return Tr[p].val;
int mid=(Tr[p].l+Tr[p].r)>>1,res=-Inf;
if(l<=mid) checkMax(res,queryMax(ls,l,r));
if(mid<r) checkMax(res,queryMax(rs,l,r));
return res;
}
inline int get(int sl,int sr)
{
int l=sl,r=sr,res=r;
while(l<=r)
{
int mid=(l+r)>>1;
if(val[mid]==val[sr]) res=mid,r=mid-1;
else l=mid+1;
}
return res;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(N);
for(int i=1;i<=N;++i) read(val[i]);
build(1,1,N);
read(Q);
for(int ql,qr;Q--;)
{
read(ql,qr);qr=get(ql,qr);
if(ql==qr) puts("0");
else write(val[qr]-ql+queryMax(1,ql,qr),'\n');
}
return 0;
}
/*

*/

C. 乐乐乐

题目简介

给定一个包含了 所有整数的集合 ,然后指定 个数 ,将 中删去。

然后执行若干次操作,每次取出 中的两个元素,满足 ,其中 为任意非负整数,并将 删去。

求最多能执行多少次操作。

数据范围:

首先考虑最简单的形式,即 ,那么所有数都能够形成一棵满二叉树。而我们发现可以配对 ,最后只会剩下 一个数,最多能匹配 次。

然后扩展到 为任意数。这道题里我们当然没有办法将完全二叉树拆分成 棵满二叉树,因为子树并不合法。

这里我们设 ,那么这棵树少了 的结点,那么 就无法被配对。然后你发现这就是个 的子问题,所以我们直接递归处理。

时间复杂度


然后考虑 的限制。但我们依然考虑优先匹配叶结点,然后将 归于子问题,进行递归,所以我们只需要处理 被删除的结点的贡献。

如果这个点不是叶结点,那其匹配的叶结点就无法匹配,所以答案 ;但如果这个点是叶结点,那么与之匹配的父亲就会空出来,我们设空出的结点的集合为

对于 ,首先考虑其是否能够自匹配,也就是匹配到 中去,那么连边后会形成森林结构,贪心是正确的。否则,我们将其与其在 中的父亲匹配,并将这些父亲视作被删除的结点。

然后搞个哈希之类的维护一下,滚动一下数组,时间复杂度

AC Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// ----- Eternally question-----
// Problem: #2694. [2023CSP七连 附加赛1] 乐乐乐
// Contest:
// URL: http://zhengruioi.com/problem/2694
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// Written by: Eternity
// Time: 2023-10-04 16:37:03
// ----- Endless solution-------

#include<bits/stdc++.h>
#define re register
typedef long long ll;
typedef unsigned long long ull;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1){ read(x),read(x1...); }
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<>
inline void write(bool x){ putchar(x?'1':'0'); }
template<>
inline void write(char c){ putchar(c); }
template<>
inline void write(char *s){ while(*s!='\0') putchar(*s++); }
template<>
inline void write(const char *s){ while(*s!='\0') putchar(*s++); }
template<class T,class ...T1>
inline void write(T x,T1 ...x1){ write(x),write(x1...); }
template<class T>
inline bool checkMax(T &x,T y){ return x<y?x=y,1:0; }
template<class T>
inline bool checkMin(T &x,T y){ return x>y?x=y,1:0; }
#define clz(x) __builtin_clzll(x)
const int MAXM=1e5+10;
int M,Id;
ull N,Pos[2][MAXM],Rt[MAXM],tmp[MAXM],ans;
bool Vis[MAXM];
std::unordered_map<ull,int>Hash,Bck;
std::vector<int>Edges[MAXM];
inline ull get(ull x){ return 1ull<<(64-clz(x)); }
void dfsTr(int x)
{
bool ok=0;Vis[x]=0;
for(int v:Edges[x]) dfsTr(v),ok|=(!Vis[v]);
if(ok) Vis[x]=1,++ans;
}
void solve(ull x,int op,int len)
{
if(x<=2) return ;
if(x<=5000){ int ccc=x;while(ccc--); }
int cnt=0,lcnt=0,rcnt=0;
Bck.clear();
ull bt=get(x),nx=bt-(x+1);
ans+=x-(bt>>1);
for(int i=1;i<=len;++i)
{
if(Pos[op][i]>=bt-Pos[op][i])
{
if(Hash.find(bt-Pos[op][i])==Hash.end())
tmp[++cnt]=bt-Pos[op][i],Bck[bt-Pos[op][i]]=cnt,--ans;
}
else if(Pos[op][i]>nx) --ans;
else Pos[op^1][++lcnt]=Pos[op][i];
}
for(int i=1;i<=cnt;++i) std::vector<int>().swap(Edges[i]);
for(int i=1;i<=cnt;++i)
{
ull val=get(tmp[i])-tmp[i];
if(val==tmp[i]||val<=nx){ Rt[++rcnt]=i;continue; }
if((Id=Bck[val])) Edges[Id].push_back(i);
else Rt[++rcnt]=i;
}
for(int i=1;i<=rcnt;++i)
if(dfsTr(Rt[i]),!Vis[Rt[i]])
{
ull val=get(tmp[Rt[i]])-tmp[Rt[i]];
if(val<=nx&&Hash.find(val)==Hash.end())
Pos[op^1][++lcnt]=val,Hash[val]=1,++ans;
}
solve(nx,op^1,lcnt);
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(N,M);
for(int i=1;i<=M;++i) read(Pos[0][i]),Hash[Pos[0][i]]=1;
solve(N,0,M);
write(ans);
return 0;
}
/*

*/