牛客练习赛115

https://ac.nowcoder.com/acm/contest/64819

A Mountain sequence

题意

定义序列 aa 为山峰序列当存在一个 jj 满足: aiai+1(1ij1),aiai+1(jin1)a_i\leq a_{i+1}(1\leq i\leq j-1),a_i\geq a_{i+1}(j\leq i\leq n-1)。现给定一个长度为 nn 的序列,有多少种方法可以使重排后的序列为山峰序列。

数据范围:1n1051\leq n\leq 10^5

题解

最大值一定会放在中间。然后接着考虑次大值,假设它有 xx 个,那么一共有 x+1x+1 种方案:全放左边,11 个放右边……全放右边。依此类推,可以得到答案就是除最大值以外的所有值出现次数加一的乘积。

代码

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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p=998244353;
map<int,int> mp;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;cin>>t;
while(t--)
{
mp.clear();
int n;cin>>n;
int mx=1;
for(int i=1;i<=n;i++)
{
int a;cin>>a;
mp[a]++;
mx=max(mx,a);
}
ll ans=1;
for(auto i:mp)
if(i.first!=mx) ans=ans*(i.second+1)%p;
cout<<ans<<'\n';
}
return 0;
}

C Find the maximum slope

题意

给定一个长度为 nn 的数组 aa。并给出 qq 次操作:每次将一个区间内的数加上 xx。定义一个数组的倾斜度为 max1i,jn,ijaiajij\max_{1\leq i,j\leq n,i\neq j}|\dfrac{a_i-a_j}{i-j}|。求出最初和每次操作后的倾斜度。

数据范围:2n5×105,1q1052\leq n\leq 5\times 10^5,1\leq q\leq 10^5

题解

一个重要的观察是:倾斜度一定在相邻两点处取到。考虑两点中间的一个点,它与两点斜率至少有一个不小于两点连线的斜率(画个图就能发现)。所以,问题就成了求 maxaiai1\max|a_i-a_{i-1}|,差分数组然后multiset维护一下就可以了。

代码

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
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int a[N],d[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,q;cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
multiset<int,greater<int>> s;
for(int i=1;i<n;i++) d[i]=a[i+1]-a[i],s.insert(abs(d[i]));
cout<<*s.begin()<<'\n';
while(q--)
{
int l,r,x;cin>>l>>r>>x;
if(l!=1)
{
s.erase(s.lower_bound(abs(d[l-1])));
d[l-1]+=x;
s.insert(abs(d[l-1]));
}
if(r!=n)
{
s.erase(s.lower_bound(abs(d[r])));
d[r]-=x;
s.insert(abs(d[r]));
}
cout<<*s.begin()<<'\n';
}
return 0;
}

D Genealogy in the trees

题意

给定一棵 nn 个结点的根为 11 的树,树边为父结点向子结点的有向边。给出 mm 个点对 (pi,qi)(p_i,q_i)qq 次询问。每次询问给出点对 (a,b)(a,b),回答有多少个 ii 满足 pip_i 可以到达 aa 并且 bb 可以到达 qiq_i

数据范围:1n,m,q3×1051\leq n,m,q\leq 3\times 10^5

题解

dfs。当遇到 pip_i 时,在 qiq_i 位置加一,当遇到 aia_i 时,对 bib_i 求子树内贡献和,离开 pip_i 时,qiq_i 位置减一。dfs序+树状数组就可以实现。

代码

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
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,q,c[N],qry[N];
int dfn,l[N],r[N];
vector<int> g[N],p[N];
vector<pair<int,int>> a[N];
int lowbit(int x) {return x&-x;}
void add(int x,int k)
{
while(x<=n)
{
c[x]+=k;
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x)
{
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
int query(int l,int r) {return query(r)-query(l-1);}
void dfs0(int u,int fa)
{
l[u]=++dfn;
for(int v:g[u])
if(v!=fa) dfs0(v,u);
r[u]=dfn;
}
void dfs(int u,int fa)
{
for(int i:p[u]) add(l[i],1);
for(auto i:a[u]) qry[i.first]=query(l[i.second],r[i.second]);
for(int v:g[u])
if(v!=fa) dfs(v,u);
for(int i:p[u]) add(l[i],-1);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>m>>q;
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
g[u].push_back(v),g[v].push_back(u);
}
for(int i=1;i<=m;i++)
{
int x,y;cin>>x>>y;
p[x].push_back(y);
}
for(int i=1;i<=q;i++)
{
int x,y;cin>>x>>y;
a[x].push_back({i,y});
}
dfs0(1,0);
dfs(1,0);
for(int i=1;i<=q;i++) cout<<qry[i]<<'\n';
return 0;
}

F Jewel maximizing magic

题意

给定一个 nn 个数的可重集合,每次取出两个数,并将两个数的异或放回集合。问 n1n-1 次操作放回的所有数异或和最大为多少。

数据范围:1n3×105,0ai<10241\leq n\leq 3\times 10^5,0\leq a_i<1024

题解

该问题等价于 nn 个数里挑 kk 个数异或起来的最大值。nnkk 有这样的关系:(nmod3)+(kmod3)1(mod3)(n\bmod 3)+(k\bmod 3)\equiv 1\pmod 3。然后直接dp就行了。


牛客练习赛115
https://je3ter.github.io/2023/09/11/ACM/牛客练习赛115/
作者
Je3ter
发布于
2023年9月11日
许可协议