Spectral::Cup 2026 Round 1 (Codeforces Round 1094, Div. 1 + Div. 2)做题报告和补题
赛时 2 题
A. A Wonderful Contest
思路:观察数据范围很小,直接暴力做
B. Artistic Balance Tree
知识点:思维
思路:观察变换情况,发现变换前后坐标的奇偶性不会变,而且对于任何一个 \(x_i\),可以把任何同奇偶坐标的元素移动到这个位置进行标记,所以我们把奇偶坐标处所对应的元素分别存起来;任务是找出所有未标记元素的最小和,也就是让标记元素的和最大,所以计算有多少个 \(x_i\) 是奇数,多少是偶数,从各自序列里取正数就行了,如果取完了正数,因为可以反复标记,不标记负数,只标记正数就可以了,(特殊情况是序列里全是负数,但必须取一个,取最大的就行了)
Code
点击查看代码
void solve()
{
cin >> n >> m;
vi a(n);
int sum = 0;
vi ji, ou;
for (int i = 0; i < n; i++)
{
cin >> a[i];
sum += a[i];
if ((i + 1) % 2 == 1)
{
ji.push_back(a[i]);
}
else
{
ou.push_back(a[i]);
}
}
int j = 0, o = 0;
for (int i = 0; i < m; i++)
{
cin >> x;
if (x % 2 == 1)
{
j++;
}
else
{
o++;
}
}
sort(ji.rbegin(), ji.rend());
sort(ou.rbegin(), ou.rend());
int rj = 0;
if (j > 0 && !ji.empty())
{
rj = ji[0];
int mx = min(j, (int)ji.size());
for (int i = 1; i < mx; i++)
{
if (ji[i] > 0)
{
rj += ji[i];
}
else
{
break;
}
}
}
int ro = 0;
if (o > 0 && !ou.empty())
{
ro = ou[0];
int mx = min(o, (int)ou.size());
for (int i = 1; i < mx; i++)
{
if (ou[i] > 0)
{
ro += ou[i];
}
else
{
break;
}
}
}
int ans = sum - (rj + ro);
cout << ans << endl;
}
C. Median Partition
知识点:dp
思路:先看数据范围,是 \(5e3\),可以进行 \(O(n^2)\) 的算法,注意到这个题不能排序,如果贪心着做容易漏情况,所以看看 dp 的做法
枚举区间的起点,同时枚举上一个区间的终点,如果该区间是合法的,那应该满足以下条件
\(
\left\{\begin{matrix}
大于mid的数的二倍小于区间长度, & \\
小于mid的数的二倍小于区间长度, & \\
区间长度为奇数,&
\end{matrix}\right
.
\)
如果我们分别预处理出大于和小于 \(mid\) 的数的前缀和,就可以在 \(O(1)\) 的时间内判断区间是否合法
Code
点击查看代码
void solve()
{
cin >> n;
vi a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
vi b = a;
sort(b.begin() + 1, b.end());
int mid = (n + 1) / 2;
int num = b[mid];
vi p1(n + 1), p2(n + 1);
for (int i = 1; i <= n; i++)
{
p1[i] = p1[i - 1];
p2[i] = p2[i - 1];
if (a[i] >= num)
{
p1[i]++;
}
if (a[i] <= num)
{
p2[i]++;
}
}
vi dp(n + 1, -1);//因为区间必须相邻,所以初始时除0外所有点作为末端都是不合法的
dp[0] = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= i; j++)
{
if ((i - j) & 1)
{
int len = i - j;
if (p1[i] - p1[j] > len / 2 && p2[i] - p2[j] > len / 2 && dp[j] != -1)
{
dp[i] = max(dp[i], dp[j] + 1);
}
}
else
{
continue;
}
}
}
cout << dp[n] << endl;
}
D. Permutation Construction
知识点:前缀和,思维
思路:对于题目中所说的价值,可翻译为 \(s_{j-1}-s_{i-1}\),也就是前缀和相减,那么该如何构造呢?对于前缀和 \(s_{i-1}\) 越大的位置,我们越要利用这个大值来和别的构成逆序对获得更大的收益,所以对于最大前缀和,给它赋值最小的 \(1\) 是最合理的,以此类推
注意:原题目中所说的{i,j}为逆序对,说的是排列中的下标{i,j},也就是满足 i<j&&p_i>p_j的一对数
点击查看代码
struct node
{
int val, id;
};
bool cmp(node a, node b)
{
if (a.val == b.val)
{
return a.id < b.id;
}
return a.val > b.val;
}
void solve()
{
cin >> n;
vi a(n + 1);
vector<node> p(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
p[i].val = p[i - 1].val + a[i - 1];//计算 s[i-1]
p[i].id = i;
}
sort(p.begin() + 1, p.end(), cmp);
vi res(n + 1);
for (int i = 1; i <= n; i++)
{
res[p[i].id] = i;
}
for (int i = 1; i <= n; i++)
{
cout << res[i] << endl;
}
cout << endl;
}

浙公网安备 33010602011771号