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_赛后总结的主要内容,如果未能解决你的问题,请参考以下文章