Educational Codeforces Round 151 (Rated for Div. 2)

D. Rating System

题意

给出一个得分序列。可以设定一个 kk,使得分数到达 kk 后不会再低于 kk。求一个 kk 使得最终得分最大。

题解

显然 kk 应该为得分序列前缀和中的一个。对于给定的 k=sumik=sum_i,必然存在一个位置 j[i,n]j\in[i,n],使得从该位置往后得分不再小于 kk。所以我们直接维护后缀最大值即可(即假定从每个位置开始,得分不再小于 kk ,如果真实情况会出现小于 kk ,答案只会更差)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
int a[maxn];
ll pre[maxn],suf[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;cin>>t;
while(t--)
{
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],pre[i]=pre[i-1]+a[i];
suf[n+1]=0;
for(int i=n;i;i--) suf[i]=suf[i+1]+a[i];
for(int i=n;i;i--) suf[i]=max(suf[i],suf[i+1]);
ll idx=-0x3f3f3f3f3f3f3f3f,mx=-0x3f3f3f3f3f3f3f3f;
for(int i=0;i<=n;i++)
{
ll ans=pre[i]+suf[i+1];
if(ans>mx) idx=pre[i],mx=ans;
}
cout<<idx<<'\n';
}
return 0;
}

E. Boxes and Balls

题意

给出 nn 个盒子,有些装有一个球,有些没有装球。每次操作可以选择相邻的两个盒子且一个为空,一个不为空,将球从不为空的盒子移动到为空的盒子。求 kk 次操作后有多少种可能的情况。

题解

先考虑一个子问题,对于两种情况如何用最少的操作次数从一种变成另一种,答案很显然,每个球对应地移动。即第一个球对应移动到第一个球的位置,以此类推。

这类计数问题自然想到dp。令 fi,j,kf_{i,j,k} 表示前 ii 个位置有 jj11 用了 kk 次操作的方案数。那么有转移 fi,j,k=fi1,j1,kcostf_{i,j,k}=f_{i-1,j-1,k-cost},其中 costcost 为将第 jj11 移动到 ii 的代价。但复杂度为 O(n2k)O(n^2k),还需要优化。

kk11 移出某个区间或移入的代价是 O(k2)O(k^2) 的,所以当前位置前缀和的变化不会超过 k\sqrt{k}。这样时间复杂度就降到 O(nkk)O(nk\sqrt{k}) 了。

注意,统计答案的时候需要统计与 kk 奇偶性相同的所有操作次数。因为可以通过两次连续的交换令 kk 减少 22 而不产生影响。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <bits/stdc++.h>
using namespace std;
const int p=1e9+7;
const int B=40;
int a[1505],s[1505],f[1505][1505];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
vector<int> pos;
for(int i=1;i<=n;i++)
if(a[i]) pos.push_back(i);
int S=(int)pos.size();
f[0][0]=1;
for(int i=1;i<=n;i++)
{
int r=min(min(i,S),s[i]+B);
int l=max(1,s[i]-B);
for(int j=r;j>=l;j--)
{
int cost=abs(pos[j-1]-i);
for(int t=k;t>=cost;t--)
f[j][t]=(f[j][t]+f[j-1][t-cost])%p;
}
}
int ans=0;
for(int i=k;i>=0;i-=2) ans=(ans+f[S][i])%p;
cout<<ans<<'\n';
return 0;
}

Educational Codeforces Round 151 (Rated for Div. 2)
https://je3ter.github.io/2023/06/29/ACM/Educational Codeforces Round 151 (Rated for Div. 2)/
作者
Je3ter
发布于
2023年6月29日
许可协议