2022 ICPC网络预选赛1

A
最难的一点就是没有处理环形后效性
比如询问L=1R=9 ->111000111应该是长度为6的连续一段1,贡献为6/2=3而不是2+2=4
做法就是预处理L右边最近的0的下标x,预处理R左边最近的0的下标y,然后把一段区间分成三份求解,中间就直接贡献sum[y]-sum[x-1]
然后把左边和右边连续的1加起来除于2
做法1,dp处理前缀和贡献
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
int n,m,sum[N],L[N],R[N];
int f[N],l,r;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m>>s+1;
int cnt=0;
for(int i=1;i<=n;i++){
if(s[i]=='1')cnt++;
else cnt=0;
f[i]=f[i-cnt-1]+(cnt+1)/2;
}
L[0]=0;
for(int i=1;i<=n;i++){
if(s[i]=='1')L[i]=L[i-1];
else L[i]=i;
}
R[n+1]=n+1;
for(int i=n;i>=1;i--){
if(s[i]=='1')R[i]=R[i+1];
else R[i]=i;
}
while(m--){
cin>>l>>r;
int len=r-l+1;
int cnt1=r-L[r]+R[l]-l;
int t=f[L[r]]-f[R[l]-1]+(cnt1+1)/2;
cout<<max(0,len/3-t)<<'\n';
}
}
做法2,对一段连续的1采取贡献差分,也就是+1+0+1+0+1+0,然后前缀和
这样可以保证奇数的时候上取整,偶数下取整
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
int n,m,sum[N],L[N],R[N];
int cal(int l,int r){
int ll=R[l];
int rr=L[r];
if(ll>=rr)return (r-l+1)/2;
int len1=(r-rr)+(ll-l);
return sum[rr]-sum[ll-1]+(len1+1)/2;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m>>s+1;
// for(int i=1;i<=n;i++){
// if(s[i]=='1'&&s[i-1]!='1')sum[i]=1;
// sum[i]+=sum[i-1];
// }
int last=-1;
for(int i = 1; i <= n ; i ++ )
{
if(s[i] == '1')
{
if(last != i - 1) sum[i] = 1, last = i;
else last = -1;
}
sum[i] += sum[i - 1];
}
for(int i=1;i<=n;i++){
if(s[i]=='0')L[i]=i;
else L[i]=L[i-1];
}
R[n+1]=n+1;
for(int i=n;i>=1;i--){
if(s[i]=='0')R[i]=i;
else R[i

本文详细分析了2022年ICPC网络预选赛中涉及的算法问题,包括动态规划、优先队列、递归搜索等策略。通过实例解析A、B、C、D等题目的解题方法,如处理环形后效性、状态压缩和二分查找等技巧,并探讨了赛时思考与抽象能力的重要性。
2301

被折叠的 条评论
为什么被折叠?



