【题解】牛客 IOI 周赛 28 - 普及组题解

注意到我并不会在本题解中穿插所有部分分的拿分方法,若需要请左转明天下午的出题人讲评:https://www.nowcoder.com/live/634/1/live
录播:https://www.bilibili.com/video/BV1vA411F7hY

下发文件链接及提取码:链接:https://pan.baidu.com/s/1TUzgHsMvyvuY7mam7XRAIQ,提取码:eszx

统计 & 难度情况

统计:

  • AK 人数:12 人
  • A 题通过率:240/537,
  • B 题通过率:42/1082,
  • C 题通过率:88/650,
  • D 题通过率:15/297,

总体而言,大致符合预期。

综合难度:

  • A 题最易,对标 J 组 T1
  • B 题最难,对标 J 组 T3
  • C 题次易,对标 J 组 T4
  • D 题次难,对标 J 组 T2

代码难度排列 ACDB,思维难度排列 AC(B=D),选手参赛数据反映的难度大致符合预期。

A - String Game

本来用的是另外一题,但后来被毙了。

注意到 次操作与不操作是等价的,于是我们拆分 次操作可以抵消,只要关注 即可。

可以用 快速算出,剩下部分模拟即可。

代码:

#include <cstdio>

#define int long long
using namespace std;
int n, x;
char s[100010];
signed main(){
    scanf("%lld%lld", &n, &x);
    scanf("%s", s);
    int m = x % n;
    for(int i = m ; i < n ; i++) printf("%c", s[i]);
    for(int i = 0 ; i < m ; i++) printf("%c", s[i]);
    return 0;
}

B - Sequence Game

(下文中 LIS 表示最长上升子序列)

考虑 DP,设 为确定了前 个数, 确定为 的 LIS。

那么有转移方程:,其中

由题我们知道 ,注意到对于相同的 DP 值, 越小一定越优秀。所以我们把第一维消掉。

表示 的最小 ,我们双指针维护 的信息,最后输出存在 值的最大的 即可。

代码:

#include <cstdio>
#include <algorithm>

#define N 5010
#define INF 1000000010
using namespace std;
int n, k;
int a[N];
int v[N], dp[N];
int main(){
    scanf("%d%d", &k, &n);
    for(int i = 1 ; i <= n ; i++) v[i] = INF;
    for(int i = 1 ; i <= n ; i++){
        for(int j = 1 ; j <= k ; j++) scanf("%d", &a[j]);
        int p = 0;
        for(int j = 1 ; j <= k ; j++){
            while(p + 1 <= n && v[p + 1] < a[j]) p++;
            dp[j] = p + 1;
        }
        for(int j = 1 ; j <= k ; j++) v[dp[j]] = min(v[dp[j]], a[j]);
    }
    for(int j = n ; j >= 1 ; j--){
        if(v[j] != INF){
            printf("%d\n", j);
            return 0;
        }
    }
    return 0;
}

C - Simple Game

《Simple》

为了方便,令 表示从点 能到达的编号最小的点的编号。

对于点 ,很容易想到的先设 ,通过比较 (点 是点 直接到达的点)中的最大值来找到答案。

当然如果产生环,如出现如下的图时会出现死循环。

图片说明

计算 时会等待 ,而 也在等待 ,这样就无法计算出答案。

而这样,我们可以考虑反向建边,即对于边 ,我们建成

遍历 ,从点 ,对于 能到达的所有点 ,若 还没有更新,则

由于 是从小到大枚举的,所以得到的答案必然是正确的。

当然,要去重。

代码:

#include <cstdio>
#include <vector>
#include <algorithm>

#define N 100010
using namespace std;
int n, m;
int a[N];
vector <int> p[N];
void Solve(int x, int v){
    a[x] = v;
    for(int i = 0 ; i < p[x].size() ; i++)
        if(a[p[x][i]] == 0)
            Solve(p[x][i], v);
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 0 ; i < m ; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        p[v].push_back(u);
    }
    for(int i = 1 ; i <= n ; i++)
        if(!a[i]) Solve(i, i);
    sort(a + 1, a + n + 1);
    n = unique(a + 1, a + n + 1) - a - 1;
    for(int i = 1 ; i <= n ; i++)
        printf("%d ", a[i]);
    return 0;
}

D - Sweet Game

注意到我们可以这样构造 Cindy 的吃糖顺序:

  • 首先,将糖 添加到序列中。
  • 然后我们将糖 添加到糖 的左侧或右侧。
  • 然后我们在当前糖序列的左侧或右侧添加糖
  • 接下来,在左端或右端添加糖
  • 依此类推。

我们枚举 ,对于糖 ,它只可能插入到原序列的最左边或最右边。

考虑贪心。

设插入数 前的糖序列为 ,令

  • 若将 插入 左边,则新数列对答案的贡献为
  • 若将 插入 右边,则新数列对答案的贡献为

比较一下上面两个式子即可,即比较 的大小。

  • ,则将 插入 右边。
  • ,则将 插入 右边;若 ,则将 插入 左右两侧均可。

在下面的程序中默认将 都插入左边,将 都插入右边。

代码:

#include <cstdio>

#define N 200010
#define int long long 
using namespace std;
inline int rd();
int a[N], d[N];
int n, ans[2 * N], l, r;
int k = 0;
signed main(){
    n = rd();
    l = r = 200000;
    for(int i = 1 ; i <= n ; i++) a[i] = rd();
    for(int i = 1 ; i <= n ; i++) d[i] = rd();
    ans[l] = n;
    k = d[n];
    for(int i = n - 1 ; i ; i--){
        if(k >= (n - i) * d[i]) l--, ans[l] = i;
        else r++, ans[r] = i;
        k += d[i];
    }
    int Ans = 0, j = 0;
    for(int i = l ; i <= r ; i++){
        Ans += (a[ans[i]] + j * d[ans[i]]);
        j++;
    }
    printf("%lld\n", Ans);
    return 0;
}
inline int rd(){
    char c;
    bool flag = 0;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag = 1;
    int res = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + c - '0';
    return flag ? -res : res;
}

欢迎发表对本场比赛的看法,我之后可能会在牛客出其他比赛,期待你的反馈 >_<

若需要请左转明天下午的出题人讲评:https://www.nowcoder.com/live/634/1/live

届时会给出讲评课件、pdf 版题目 & 题解的下载链接,一定要来!

图片说明

全部评论
萝莉喜提首AK
5 回复
分享
发布于 2021-08-28 21:50
还有感觉B挺平凡的吧,完全是PJ T2水准,实际上难度排的话应该是A<B<D<C
1 回复
分享
发布于 2021-08-28 21:52
联想
校招火热招聘中
官网直投
刚才我针对C题发表了一个神妙的可爱解法,但是出题人想独占我的可爱所以和我py交易以后我把评论删掉了,@CSP_Sept 姐姐你说是不是QwQ
1 回复
分享
发布于 2021-08-28 22:08
B题完全可以套LIS nlogn板子 设dp[i]表示长度为i的最小末尾传统艺能 只是要倒序枚举每个数可能的值 防止自己更新自己 先输入k再输入n 100>5pts  让本来就没能拿多少分的jr挂分 让本来就迟到的jr没时间看后面的题 差评(((
1 回复
分享
发布于 2021-08-29 00:50
为啥我觉得D最难,B不是sb题吗,在值域上dp不就行?
点赞 回复
分享
发布于 2021-08-28 21:52
请问 征集题解的活动在哪?
点赞 回复
分享
发布于 2021-08-28 21:54
C我一眼tarjan+dp(((
点赞 回复
分享
发布于 2021-08-28 21:56
先输入k再输入n调了一万年/hanx
点赞 回复
分享
发布于 2021-08-28 22:33
点赞 回复
分享
发布于 2021-08-28 22:47
CSP_Spet TQL!!
点赞 回复
分享
发布于 2021-08-29 07:13
t4似乎写了两个k>mda?大雾
点赞 回复
分享
发布于 2021-08-29 12:22
考虑一手rating选手的水平,蓝名以下记rating,蓝名以下这场能做的不多,,
点赞 回复
分享
发布于 2021-08-29 14:52
艹,错过讲评了 /ll
点赞 回复
分享
发布于 2021-08-29 15:44
B应该也能树状数组优化dp
点赞 回复
分享
发布于 2021-08-29 20:04
C洛谷上有原题吧 https://www.luogu.com.cn/problem/P3916
点赞 回复
分享
发布于 2021-08-29 21:19

相关推荐

12 2 评论
分享
牛客网
牛客企业服务