2021acm-icpc区域赛(南京)补题笔记

分享2021南京icpc区域赛解题笔记,涵盖签到题、铜牌题至金牌题的思路解析,包括前缀和优化、树形dp、数论技巧等,助你理解比赛难题

前言

2021南京,号称今年最卷的icpc区域赛。

上周末训练赛和队友打了一下,争取多补几道题。

比赛链接:https://codeforces.com/gym/103470

题目一览

签到题:A,C,M,H

铜牌题:D

银牌题:J

金牌题:I ,G

我不能做的题:B,F,K,L

本场差不多是4.5题铜,5.5题银,7题金(4题铜5题银的概率不大,约等于5铜,6银,7金)

A.Oops, It’s Yesterday Twice More(签到)

题意

不知道,队友写的

思路

不知道,队友写的

M. Windblume Festival(签到)

题意

给一个长度为n整数序列 a [ ] a[] a[] , 每次操作可以选择两个下标 i , j i,j ij ( i < j i < j i<j,环形) , 移除 a j a_j aj , 并且令 a i = a i − a j a_i = a_i - a_j ai=aiaj

最后会剩下一个元素,要求最大化这个元素。 ( 1 < = n < = 1 0 6 1<=n<=10^6 1<=n<=106)

input

5
4
1 -3 2 -4
11
91 66 73 71 32 83 72 79 84 33 93
12
91 66 73 71 32 83 72 79 84 33 33 93
13
91 66 73 71 32 83 72 79 84 33 33 33 93
1
0

output

10
713
746
779
0

Note

For the first sample test case follow the strategy shown below, where the underlined integers are the integers held by the players selected in each turn.

{1–,−3,2,−4}(select x=4) →→ {−3,2,−5} (select x=2x) →→ {−3,7} (select x=2) →→ {10}}.
思路

这是一个环形的结构,所以我们可以“自行地”决定一个数的贡献是正的还是负的。并且一定会有一个正的贡献,并且n>1时必定有一个负的贡献。

所以,答案就是 a n s = m a x − m i n + s u m ( r e s ) ans = max - min + sum(res) ans=maxmin+sum(res)

C. Klee in Solitary Confinement(思维+前缀和)

题意

给一个长度为n整数序列 a [ ] a[] a[] , 给一个正整数 k k k

可以选择一段区间 [ l , r ] [l,r] [l,r] , 将其中所以元素加 k k k

要求最大化出现次数最多的数的数量。

( 1 ≤ n ≤ 1 0 6 , − 1 0 6 ≤ k ≤ 1 0 6 , − 1 0 6 ≤ a i ≤ 1 0 6 ) (1≤n≤10^6, −10^6≤k≤10^6 ,−10^6≤a_i≤10^6) (1n106,106k106,106ai106

Examples

input

5 2
2 2 4 4 4

output

5

input

7 1
3 2 3 2 2 2 3

output

6

input

7 1
2 3 2 3 2 3 3

output

5

input

9 -100
-1 -2 1 2 -1 -2 1 -2 1

output

3
思路

不难发现,对于每个数字 i i i,我们只需要考虑 i i i i + k i+k i+k 的相对位置关系,可以忽略其他所有的数字。

所以我们可以遍历一遍数组,用 v e c t o r vector vector将每个 i i i i + k i+k i+k分在一个组里并保留相对位置。

对每个组,令 a i = 1 a_i = 1 ai=1 , a i + k = − 1 a_i+_k = -1 ai+k=1,目标就是最大化区间找出区间和最大的区间 [ l , r ] [l,r] [l,r]

意思就是对于区间 [ l , r ] [l,r] [l,r] , 我们能令最多的 a i a_i ai变成 a i + k a_i+_k ai+k 的同时,令最少的 a i + k a_i+_k ai+k被改变。

实现上,我们维护一个前缀和 sum[i] 和最小前缀和 sum_min[i] 即可。

代码
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
#define int long long
const int BASE=1e6;
const int MAXN=4e6+20;
int n,k,a,sum[MAXN/4],minn,maxn,summin[MAXN/4],cnt[MAXN],flag,ans,tot;
vector<int> s[MAXN];

void solve(int num) {
    tot=s[num].size();
    if(tot==0) return;
    ans=max(ans,cnt[num]+s[num][0]);
    sum[1]=s[num][0];
    summin[1]=min(sum[0],sum[1]);
    for(int i=2;i<=tot;++i) {
        sum[i]=sum[i-1]+s[num][i-1];
        summin[i]=min(summin[i-1],sum[i]);
        ans=max(ans,sum[i]-summin[i-1]+cnt[num]);
        //cout<<i<<" "<<sum[i]<<" "<<summin[i-1]<<'\n';
    }

    for(int i=1;i<=tot;++i) sum[i]=summin[i]=0;
}

signed main()
{
    scanf("%lld%lld",&n,&k);
    flag=1;
    if(k<0) flag=-1,k=-k;
    minn=5e6,maxn=-1;
    for(int i=1;i<=n;++i) {
        scanf("%lld",&a);
        a=a*flag+BASE;
        minn=min(minn,a);
        maxn=max(maxn,a);
        ++cnt[a];
        ans=max(ans,cnt[a]);
        s[a].push_back(-1);
        s[a+k].push_back(1);
    }
    if(k!=0)
    {
        for(int i=minn+k;i<=maxn;++i)
            solve(i);
    }
    cout<<ans;
    return 0;
} 

H. Crystalfly(树形dp)

题意

给一棵 n n n 个点带点权的树 ( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105 , 1 ≤ a i ≤ 1 0 9 1≤a_i≤10^9 1ai109)

从 1 号点出发,每个点的点权可以吃一次,要求最大化吃到的点权和。

每个点还有另一个值 t i t_i ti , 当你走到这个点的相邻节点时,这个点会被" d i s t u r b disturb disturb " , t i t_i ti 开始倒计时,如果在倒计时结束前还没能吃到这个点,那这个点的点权会消失(注意,可以经过,只是吃不到点权)。 其中 1 < = t i < = 3 1<=t_i<=3 1<=ti<=3

输入多组样例,每组样例第一行 n n n,第二行点权,第三行 t i t_i ti,然后是树边

input

2
5
1 10 100 1000 10000
1 2 1 1 1
1 2
1 3
2 4
2 5
5
1 10 100 1000 10000
1 3 1 1 1
1 2
1 3
2 4
2 5

output

10101
10111

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ACto4wLB-1649091209048)(C:\Users\xi2001\AppData\Roaming\Typora\typora-user-images\image-20220404114835027.png)]

思路

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值