AtCoder Beginner Contest 370 补题记录(A~F)

A

signed main(){
    int l,r;cin>>l>>r;
    if(!(l==1&&r==1||l!=1&&r!=1)){
        if(l==1)cout<<"Yes\n";
        else cout<<"No\n";
    }
    else cout<<"Invalid\n";
}

B

signed main(){
    int n;cin>>n;
    F(i,1,n)F(j,1,i)cin>>a[i][j];
    int now=1;
    F(i,1,n)
        if(i>=now)now=a[i][now];
        else now=a[now][i];
    cout<<now<<'\n';
}

C

观察到 n 很小,因此考虑暴力枚举每一个满足 sitii 并计算出修改这个位置的 siti 之后的字符串,将所有这样的字符串集合 S 按照字典序从小到大排序之后贪心选择当前字典序最小的即可。时间复杂度为 O(n3logn)

const int N=1000100,mod=1e9+7;
char s[N],t[N];
signed main(){
    scanf("%s%s",s+1,t+1);
    vector<string>v;
    int n=strlen(s+1);
    int cnt=0;
    F(i,1,n)
        if(s[i]!=t[i])++cnt;
    F(i,1,cnt){
        vector<pair<string,int> > tv;
        F(p,1,n){
            if(s[p]!=t[p]){
                char tt=s[p];
                s[p]=t[p];
                string o;
                F(j,1,n)o.push_back(s[j]);
                tv.eb(o,p);
                s[p]=tt;
            }
        }
        sort(rng(tv));
        s[tv[0].second]=t[tv[0].second];
        v.eb(tv[0].first);
    }
    cout<<v.size()<<'\n';
    for(auto &x:v)
        cout<<x<<'\n';
}

D

考虑开 2nset 分别记录 每一行 / 每一列 所有有障碍物的位置,然后查询位置 (x,y)

  • (x,y) 有障碍物,则直接删除。
  • 否则在 set 上二分找出 (x,y) 上面、下面、左边、右边第一个障碍物的位置。

然后更新 2nset 即可。注意到一次最多只可能删除 4 个位置,且每一个位置最多只会被删除一次,因此总的时间复杂度为 O((nm+q)lognm)

set<int>s1[N],s2[N],s3[N],s4[N];
signed main(){
    // freopen(".out","w",stdout);
    int n,m,q;cin>>n>>m>>q;
    mp.resize(n+3);
    zuo.resize(n+3);
    you.resize(n+3);
    shang.resize(m+3);
    xia.resize(m+3);
    set<PII>se;
    F(i,1,n)F(j,1,m)se.insert({i,j});
    F(i,1,n)F(j,1,m)s1[i].insert(j);
    F(i,1,m)F(j,1,n)s2[i].insert(j);
    while(q--){
        int x,y;cin>>x>>y;
        if(se.count({x,y})){
            s1[x].erase(y);
            s2[y].erase(x);
            se.erase({x,y});
        }else{
            auto i1=s1[x].upper_bound(y);
            vector<PII>cx;
            if(i1!=s1[x].end()){
                int _x=x,_y=*i1;
                cx.eb(_x,_y);
                se.erase({_x,_y});
            }
            if(i1!=s1[x].begin()){
                --i1;
                int _x=x,_y=*i1;
                cx.eb(_x,_y);
                se.erase({_x,_y});
            }
            i1=s2[y].upper_bound(x);
            vector<PII>cy;
            if(i1!=s2[y].end()){
                int _x=*i1,_y=y;
                cy.eb(_x,_y);
                se.erase({_x,_y});
            }
            if(i1!=s2[y].begin()){
                --i1;
                int _x=*i1,_y=y;
                // cout<<"wtf "<<_x<<' '<<_y<<'\n';
                cy.eb(_x,_y);
                se.erase({_x,_y});
            }
            for(auto &[_x,_y]:cx)
                s1[x].erase(_y),s2[_y].erase(x);
            for(auto &[_x,_y]:cy)
                s2[y].erase(_x),s1[_x].erase(y);
        }
        // for(auto &[x,y]:se)
        //     cout<<"qwq "<<x<<' '<<y<<'\n';
        // cout<<'\n';
    }
    cout<<se.size()<<'\n';
}

E

fi 表示当前枚举到的连续子序列以 i 结尾的不同方案数,显然答案为 i=1nfi,若 1jiji 一段区间的和不为 kfifj。因此可以做到 O(n2)

考虑优化,设 gi 表示当前前缀和为 if 值的和,则 g 的转移容易,fi 的转移可以优化为 fi=(j=0i1fj)g(j=1iai)k

其中 j=0i1fjj=1iai 都可以处理出,因此这样计算时间复杂度为 O(nlogn),瓶颈在于 map

O(n2) 代码

const int N=500100,mod=998244353;
int a[N],s[N],n,k,f[N];
signed main(){
    cin>>n>>k;
    F(i,1,n)cin>>a[i],s[i]=s[i-1]+a[i];
    f[0]=1;
    F(i,1,n){
        F(j,1,i)
            if(s[i]-s[j-1]!=k)
                f[i]=(f[i]+f[j-1])%mod;
    }
    cout<<f[n]<<'\n';
}

O(nlogn) 代码

const int N=500100,mod=998244353;
int a[N],s[N],n,k,f[N];
map<int,int>g;
signed main(){
    cin>>n>>k;
    F(i,1,n)cin>>a[i],s[i]=s[i-1]+a[i];
    f[0]=1;
    g[0]=1;
    int all=1;
    F(i,1,n){
        f[i]=all-g[s[i]-k];
        f[i]%=mod;f[i]+=mod;f[i]%=mod;
        all+=f[i];
        all%=mod;
        g[s[i]]+=f[i];
    }
    cout<<f[n]<<'\n';
}

F

首先套路的破换成链,然后二分答案 p

对于每一个二分的答案 p,考虑先二分出 fi,0 表示 i 之后第一个满足 j=ifi,0ajpfi,0,然后倍增的设 fi,j 表示 i 之后满足 2j 次上述条件的下标为 fi,j。特殊的若不可以满足则令 fi,j=1

然后考虑枚举起点,直接暴力倍增计算出 k 次操作之后的答案即可。时间复杂度为 O(nlog2n)。代码有点混乱。

const int N=400100,mod=998244353;
int a[N],s[N],n,k,now,nxt[N][20],res;
bool chk(int p){
    memset(nxt,-1,sizeof nxt);
    F(i,1,n+n){
        int l=i,r=i+n-1,best=-2;
        r=min(r,n+n);
        while(l<=r){
            int mid=l+r>>1;
            if(s[mid]-s[i-1]>=p)best=mid,r=mid-1;
            else l=mid+1;
        }
        nxt[i][0]=best+1;
    }
    nxt[n+n+1][0]=n+n+1;
    F(i,1,19)
        F(j,1,n+n+1)
            if(~nxt[j][i-1])
                nxt[j][i]=nxt[nxt[j][i-1]][i-1];
    // F(i,1,n+n)
    //     cout<<i<<": "<<nxt[i][0]<<' '<<nxt[i][1]<<" qwq\n";
    int cnt=0;
    F(i,1,n){
        int x=i;
        G(j,19,0)
            if(k>>j&1){
                x=nxt[x][j];
                if(x==-1||x>i+n)break;
            }
        if(x!=-1&&x<=i+n)
            ++cnt;
    }
    if(cnt)
        res=n-cnt;
    return !!cnt;
}
signed main(){
    cin>>n>>k;
    F(i,1,n)cin>>a[i],s[i]=s[i-1]+a[i];
    F(i,1,n)a[i+n]=a[i],s[i+n]=s[i+n-1]+a[i];
    int l=1,r=s[n],best=-1;
    while(l<=r){
        int mid=l+r>>1;
        if(chk(mid))best=mid,l=mid+1;
        else r=mid-1;
    }
    cout<<best<<' '<<res<<'\n';
}

posted @   yhbqwq  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
点击右上角即可分享
微信分享提示