Educational Codeforces Round 128
Educational Codeforces Round 128
C. Binary String
题意:每次可以从一个01串的两头删除0或者1,求最后留在串中的0的数量和删除的1的数量最大值最小是多少
做法:我们枚举从一端删除1的数量,那么其实你可以发现随着另一端删除1的数量增加,答案会随着变小到最小然后再变大,就类似二次函数的极值,那么我们就只需要对每一个位置三分极值即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
char s[200050];
int dp[200050];
int n;
vector<int>pos;
int check(int i,int j,int num,int zero){
if(j>=pos.size()) return 10000000;
int One=num+j;
int O=zero-(n-i+1+dp[pos[j]]-1-One);
int t=max(One,O);
return t;
}
int main(){
#ifdef lmj_debug
freopen("1.in","r",stdin);
#endif
int T;
cin>>T;
while(T--){
pos.clear();
scanf("%s",s+1);
n=strlen(s+1);
int ans=1000000;
int zero=0,one=0;
int num=0;
for (int i=1;i<=n;i++) {
if(s[i]=='0') zero++;
else {
num++;
dp[num]=i;
pos.push_back(num);
}
}
int r=n-zero;
if(r==0 || zero==0){
puts("0");
continue;
}
ans=r;
num=0;
for (int i=n+1;i>=1;i--){
if(s[i]=='1') num++;
int l=0;
r=pos.size()-1;
while(l<=r){
int mid=(l+r)>>1;
int t1=check(i,mid,num,zero);
int t2=check(i,mid+1,num,zero);
ans=min(ans,t1);
ans=min(ans,t2);
if(t1>=t2){
l=mid+1;
}else r=mid-1;
}
for (int j=max(0,l-5);j<=min((int)pos.size()-1,r+5);j++) ans=min(ans,check(i,j,num,zero));
ans=min(ans,check(i,0,num,zero));
ans=min(ans,check(i,pos.size()-1,num,zero));
}
printf("%d\n",ans);
}
return 0;
}
E. Moving Chips
题意:给一个两行的\(*和.\)的序列,最后要将所有的\(*\)都移动到一个位置,求最少需要的步数
做法:基本思路,我们可以枚举每一个\(*\)位置将所有的\(*\)转移到这个位置的代价,然后求出最小步数即可,那么问题就转化为怎么求将前面的所有\(*\)转移到每个位置的最小代价,这个dp推一下即可,
设pre[i][j]为1~ j - 1列的芯片都移动到(i,j)的最小次数,则分两种情况 (因为同一列都有芯片总要合并一起移动才最优):
1 ~ j - 1列的芯片都先移动到 (i, j - 1) ,然后再移动到(i, j)。
次数为前面的移动到(i, j - 1)的次数,加上(i^1, j - 1)移动到(i,j - 1)的次数,再加上一次
即为pre[i][j - 1] + 1+ (s[i^1][j - 1] == ‘*’)
1 ~ j - 1列的芯片都先移动到(i^1, j - 1) ,然后再移动到(i,j)
次数为pre[i^1][j - 1] + 1
同理可以计算suf[i][j]为j+1~n都移动到(i,j)的最小操作数。
那么(i,j)位置的答案要么是两个pre都在[i ^ 1,j],然后向上一步,或者两个都在(i,j),如果(i^1,j)有'*'再加上1,
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int pre[2][maxn],suf[2][maxn];
char s[2][maxn];
int main(){
#ifdef lmj_debug
freopen("1.in","r",stdin);
#endif
int T;
cin>>T;
while(T--){
int n;
scanf("%d",&n);
scanf("%s",s[0]+1);
scanf("%s",s[1]+1);
int tou=1,wei=n;
while(s[0][tou]=='.' && s[1][tou]=='.' && tou<n) tou++;
while(s[0][wei]=='.' && s[1][wei]=='.' && wei>1) wei--;
for (int i=0;i<=n;i++) pre[0][i]=pre[1][i]=suf[0][i]=suf[1][i]=0;
for (int i=tou+1;i<=n;i++) for (int j=0;j<=1;j++) pre[j][i]=min(pre[j^1][i-1]+2,pre[j][i-1]+1+(s[j^1][i-1]=='*'));
for (int i=wei-1;i>=1;i--) for (int j=0;j<=1;j++) suf[j][i]=min(suf[j^1][i+1]+2,suf[j][i+1]+1+(s[j^1][i+1]=='*'));
int ans=1e9;
for (int j=0;j<=1;j++){
for (int i=1;i<=n;i++){
if(s[j][i]=='.') continue;
ans=min(ans,pre[j][i]+suf[j][i]+(s[j^1][i]=='*'));
ans=min(ans,pre[j^1][i]+suf[j^1][i]+1);
}
}
printf("%d\n",ans);
}
return 0;
}