517_CSP-S_%你赛1_赛后总结

Posted wyctstf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了517_CSP-S_%你赛1_赛后总结相关的知识,希望对你有一定的参考价值。

A题,没有意外,比较简单的一个DP,求序列的两个最大子段和,dp[i]设断点然后O(n)在线搞一搞就出来了,刚看题的时候吓了一跳,浪费了很多时间

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 100010;

int n;
int a[maxn], dp[maxn];
int l[maxn], r[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
        f = (ch == '-') ? -1 : 1, ch = getchar();
    while (isdigit(ch))
        x = x * 10 + (ch - '0'), ch = getchar();
    return x * f;
}

main()
{
    // freopen("in.txt", "r", stdin);
    n = read();
    for (int i = 1; i <= n; i++)
        a[i] = read();
    int Max = 0, now = 0;
    
    for (int i = 1; i < n; i++)
    {
        if (now < 0)
            now = 0;
        now += a[i];
        Max = max(Max, now);
        l[i + 1] = Max;
    }

    now = 0, Max = -1;
    
    for (int i = n; i > 1; i--)
    {
        if (now < 0)
            now = 0;
        now += a[i];
        Max = max(Max, now);
        r[i] = Max;
    }
    Max = 0;
    for (int i = 1; i <= n; i++)
        Max = max(l[i] + r[i], Max);
    /* for (int i = 1; i <= n; i++)
        cout << l[i] << ' ';
    cout << '
';
    for (int i = 1; i <= n; i++)
        cout << r[i] << ' ';
    cout << '
'; */
    std::cout << Max << '
';
    return 0;
}

B题,给出一个初始长度为n的序列,初始值为0,再给出m个操作,每个操作包含 l , r , s , e 表示序列从 l 到 r 每个元素加上一个等差数列的元素值,等差数列首项为s,末项为e,给出数据满足序列每个元素无论何时都是整数,求出最后的数列

这题思考了20min,发现两个差分可以解决,于是乱搞一通,结果一直调到比赛结束都没有跳出来,直接130滚蛋,考后观摩大佬代码,发现差分数组始末位置处理错了。。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 5e5 + 10;

int n, m, l, r, s, e;
int a[maxn], b[maxn], c[maxn], ans;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
        f = (ch == '-') ? -1 : 1, ch = getchar();
    while (isdigit(ch))
        x = x * 10 + (ch - '0'), ch = getchar();
    return x * f;
}

main()
{
    n = read(), m = read();
    for (int i = 1; i <= m; i++)
    {
        l = read(), r = read(), s = read(), e = read();
        int d = (e - s) / (r - l);
        c[l] += s, c[l + 1] += d - s;
        c[r + 1] -= d + e, c[r + 2] += e;
    }
  
    for (int i = 1; i <= n; i++)
    {
        b[i] = b[i - 1] + c[i];
        a[i] = a[i - 1] + b[i];
        ans ^= a[i];
    }
  
    cout << ans << '
';
    return 0;
}

C题,刚开始的时候看了一眼觉得不可做,讲解的时候大佬们说还是个DP,然而蒟蒻在打虚拟并没有反应过来,状态根本设不出。。

设dp[i][j][k][l]表示为当前为第i位,数列总和为j,当前位值为k,l=0表示比上一个数大(统计这个是因为序列中不能出现长度为3的递减序列)

并且只能把序列中为-1的数改为其他数字

所以:

  if (val < j)
        dp[i][sum+val][val][1] += dp[i-1][sum][j][0];
        dp[i][sum+val][val][1] %= MOD;

    else
        dp[i][sum+val][val][0] += dp[i-1][sum][j][0];
        dp[i][sum+val][val][0] %= mod;
        dp[i][sum+val][val][0] += dp[i-1][sum][j][1];
        dp[i][sum+val][val][0] %= mod;

如果a[i]==-1,那么大力枚举val,否则val=a[i]
最后统计一边n的情况即可

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int mod = 1e9 + 7;

int n;
int a[45];
int dp[45][1605][45][2];

void add(int &x, int y)
{
    x += y, x %= mod;
}

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
        f = (ch == '-') ? -1 : 1, ch = getchar();
    while (isdigit(ch))
        x = x * 10 + (ch - '0'), ch = getchar();
    return x * f;
}

main()
{
    n = read();
    for (int i = 1; i <= n; i++)
        a[i] = read();
    for (int i = 1; i <= n; i++)
    {
        if (a[i] == -1)
        {
            for (int val = 0; val <= 40; val++)
            {
                if (i == 1)
                    dp[i][val][val][0] = 1;
                else
                    for (int sum = 1600; sum >= 0; sum--)
                    {
                        if (val * (i - 1) > sum)
                            continue;
                        for (int j = 0; j <= 40; j++)
                        {
                            if (val < j)
                                add(dp[i][sum + val][val][1], dp[i - 1][sum][j][0]);
                            else
                                add(dp[i][sum + val][val][0], dp[i - 1][sum][j][0]),
                                    add(dp[i][sum + val][val][0], dp[i - 1][sum][j][1]);
                        }
                    }
            }
        }
        else
        {
            if (i == 1)
                dp[i][a[i]][a[i]][0] = 1;
            else
                for (int sum = 1600; sum >= 0; sum--)
                {

                    if (a[i] * (i - 1) > sum)
                        continue;

                    for (int j = 0; j <= 40; j++)
                    {
                        if (a[i] < j)
                            add(dp[i][sum + a[i]][a[i]][1], dp[i - 1][sum][j][0]);
                        else
                            add(dp[i][sum + a[i]][a[i]][0], dp[i - 1][sum][j][0]),
                                add(dp[i][sum + a[i]][a[i]][0], dp[i - 1][sum][j][1]);
                    }
                }
        }
    }
    int ans = 0;
    for (int sum = 0; sum <= 1600; sum++)
        for (int i = 0; i <= 40; i++)
            for (int j = 0; j <= 1; j++)
                if (dp[j])
                    add(ans, dp[n][sum][i][j]);
    printf("%d
", ans);
    return 0;
}

以上是关于517_CSP-S_%你赛1_赛后总结的主要内容,如果未能解决你的问题,请参考以下文章

XJOI CSP-S2 2019开放模拟训练题1 赛后总结

1001CSP-S模拟测试赛后总结

CSP-S2019 退役记/赛后总结

0910CSP-S模拟测试赛后总结

1002CSP-S模拟测试赛后总结

0922CSP-S模拟测试赛后总结