E. Pchelyonok and Segments
我们发现 k {k} k可以是答案的前提是线段的长度总和不超过 n {n} n。即 k ∗ ( k + 1 ) 2 ≤ n \frac{k*(k+1)}{2}\le n 2k∗(k+1)≤n, k ≤ 447 k\le 447 k≤447
令 d p i , j dp_{i,j} dpi,j表示长度为 j j j的段的最大和,同时我们已经考虑了后缀 i i i上所有的元素,并且选择了长度为 j , j − 1 , . . . , 1 {j,j-1,...,1} j,j−1,...,1的段,其中段的总和增加。
1.我们可以在长度为 j {j} j的段中包含元数 i {i} i:
dp[i][j]=dp[i+1][j]
2.或者包含元素 i {i} i,前提是 d p i + j , j − 1 dp_{i+j,j-1} dpi+j,j−1的值大于段 i , i + 1 , . . . i + j − 1 {i,i+1,...i+j-1} i,i+1,...i+j−1上的总和。
dp[i][j]=max(dp[i+1][j],sum[i+j-1]-sum[i-1])
code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+7,inf=1e9+7;
int n,a[maxn],dp[maxn][450];
ll sum[maxn];
inline void solve() {
cin>>n;
for(int i=1;i<=n;++i) {
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
int k(0);
while(k*(k+1)/2<=n) ++k;
for(int i=1;i<k;++i) dp[n+1][i]=-inf;
dp[n+1][0]=inf;
for(int i=n;i;--i) {
for(int j=0;j<k;++j) {
dp[i][j]=dp[i+1][j];
if( j && i+j-1<=n && sum[i+j-1]-sum[i-1]<dp[i+j][j-1] ) {
dp[i][j]=max(dp[i][j],(int)(sum[i+j-1]-sum[i-1]));
}
}
}
int ans(0);
for(int i=1;i<k;++i) if(dp[1][i]>0) ans=i;
cout<<ans<<'\n';
}
int main() {
cin.sync_with_stdio(false), cin.tie(nullptr),cout.tie(nullptr);
int _;
cin>>_;
while(_--) solve();
return 0;
}
Educational Codeforces Round 111 (Rated for Div. 2)
A. Find The Array
列出
1
10
1~10
1 10的一个
b
e
a
u
t
i
f
u
l
a
r
r
a
y
beautiful\ array
beautiful array:
1.1
2.1+1
3.1+2
4.1+3
5.1+3+1
。。。
9.1+3+5
10.1+3+5+1
会发现,其实就是要用公差为2,首项为1的等差数列表示一个数,如果小了就补上一个数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
int n;
inline void solve() {
int cnt(0),x(1);
cin>>n;
while(x<=n) {
n-=x; cnt+=1; x+=2;
}
if(n) cnt+=1;
cout<<cnt<<'\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
cin>>_;
while(_--) solve();
return 0;
}
B. Maximum Cost Deletion
由乘法法则其实知道答案一定要加上
a
∗
n
a*n
a∗n,我们通过改变合并的次数来改变
b
b
b的数量。
其次,整个字符串中0相邻的段和1相邻的段数量之差小于等于1。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
int n,a,b;
string s;
inline void solve() {
int cnt(0);
cin>>n>>a>>b>>s;
s=" "+s;
for(int i=1;i<=n;++i) if(s[i]!=s[i-1]) cnt+=1;
if(b<0) cout<<a*n+(cnt/2+1)*b<<'\n';
else cout<<(a+b)*n<<'\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
cin>>_;
while(_--) solve();
return 0;
}
C. Manhattan Subarrays
看完案例,以下标为x轴画图理解后,会发现如果有三个元素在原数组中不递增或者不递减就不符合条件。最直接的价值就是说,符合条件的连续子序列的个数不会超过4个,也就是告诉你可以暴力。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
int n,a[maxn];
bool check(int l,int r) {
for(int i=l;i<r;++i)
for(int j=i+1;j<r;++j)
for(int k=j+1;k<=r;++k) if((a[i]<=a[j]&&a[j]<=a[k])||(a[i]>=a[j]&&a[j]>=a[k])) return false;
return true;
}
inline void solve() {
int ans=-1;
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1,x;i<=n;++i) {
ans+=2;
for(x=i+2;x<=n;++x)
if(check(i,x)) ++ans;
else break;
}
cout<<ans<<'\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _=1;
cin>>_;
while(_--) solve();
return 0;
}