牛客周赛 Round 97

A. 回文串

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    char a,b,c;
    cin>>a>>b>>c;

    if(a==b || a==c || b==c){
        cout<<"YES";
    }
    else cout<<"NO";
}


signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

B. 2025

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n,val=1;
    cin>>n;

    while(n){
        int tmp=n%10;
        n/=10;
        val*=tmp;
    }
    // cout<<val<<endl;

    for(int i=0;i<=1000000;i++){
        if(i*i==val){
            cout<<"YES";
            return;
        }
    }

    cout<<"NO\n";
}


signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

数据范围n和q是2e5, 如果每次询问都o(n)的做一遍,复杂度是4e10, 不可接受

考虑对每次询问如何 o(1) 的计算答案

每次询问的x,y中,中间需要跳过的障碍物距离,即为x后面第一个障碍物的位置,到y前面第一个障碍物的位置 的距离

所以,可以预先用前后缀和维护出,每个位置,前一个和后一个障碍物的位置,这样在每次询问时,就可以o(1)的得到答案

代码实现中还需要考虑x,y中间没有障碍物的情况

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n,q;
    cin>>n>>q;

    string s;
    cin>>s;

    s=" "+s;

    vector<int> pre(n+10),suf(n+10,n+1);

    for(int i=1;i<=n;i++){
        pre[i]=pre[i-1];//当前位置前最近的障碍物
        if(s[i]=='#') pre[i]=i;
    }

    for(int i=n;i>=1;i--){
        suf[i]=suf[i+1];
        if(s[i]=='#') suf[i]=i;
    }

    while(q--){
        int a,b;
        cin>>a>>b;
        int x=min(a,b),y=max(a,b);

        if(suf[x]>y || pre[y]<x){
            cout<<0<<endl;
            continue;
        }

        cout<<pre[y]-suf[x]+1<<endl;
    }
}


signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

D. 字符串操作

因为要让字典序尽可能大,所以样让从前往后每个位置都尽可能大

所以先找到第一个不是 z 的位置,让这个位置右移 cnt 次,变成 z。

这个位置就是选中的子字符串开始的位置,同时右移次数也确定为 cnt 次

从这个位置的下一个开始,让每个位置都右移 cnt 次,直到某个位置,右移 cnt 次后反而变小,则变小位置的上一个位置就是子字符串的结束位置

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;
    string s;
    cin>>s;

    s=" "+s;

    vector<int> a(n+10);
    int pos=0;
    for(int i=1;i<=n;i++){
        a[i]=s[i]-'a';
        if(a[i]!=25 && pos==0){
            pos=i;
        }
    }

    if(pos==0){
        for(int i=1;i<=n;i++){
            cout<<s[i];
        }
        return;
    }

    int cnt=25-a[pos];

    for(int i=pos;i<=n;i++){
        if(a[i]+cnt>25) break;
        a[i]+=cnt;
    }

    for(int i=1;i<=n;i++){
        cout<<(char)('a'+a[i]);
    }
}


signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

E. 平衡排列

首先考虑不存在的情况,当 1-n 的和为奇数时,一定不存在平衡序列

此时 1-n 的和为偶数,一定存在平衡序列,假设 1-n 的和是sum

我们需要构造一个排列,同时找到一个位置,让小于等于这个位置的和等于 sum/2 ,此时大于这个位置的和也等于sum/2

所以只考虑构造排列的前半部分即可

我们需要的数是 need = sum/2, 从n到1循环i,只要need大于等于当前的i,就把need放进排列的前半部分,同时让need -= i

当need小于当前的i时,直接把当前的need放进排列的前半部分

此时再把 1-n 所有没有被用过的数放进前半部分即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;
    
    int sum=(1+n)*n/2;

    if(sum&1){
        cout<<-1<<endl;
        return;
    }

    map<int,int> used;
    vector<int> ans;
    sum/=2;

    for(int i=n;i>=1;i--){
        if(sum>=i){
            ans.push_back(i);
            used[i]=1;
            sum-=i;
        }
        else{
            if(sum>0){
                ans.push_back(sum);
                used[sum]=1;
            }
            break;
        }
    }

    for(int i=1;i<=n;i++){
        if(!used[i]) ans.push_back(i);
    }

    for(auto val:ans){
        cout<<val<<" ";
    }
    cout<<endl;
}


signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

F. 小苯的序列分段

只需要考虑,bi 和 bi+1 之间,有cnt个位置可以分割,再把每个cnt乘起来即可

分别考虑 bi 和 bi+1 在区间 bi 到 bi+1 中可以分割的位置

用单调栈处理出,每个位置后面第一个比它大的位置 ri,和每个位置前面第一个比它大的位置 li

bi 和 bi+1 的cnt即为区间 bi 到 bi+1 中,ri 和 li+1 的交集

例如:

3 1 2 4 5, b是3,5

则ri是位置4(对应的数是4,注意要和bi+1的位置取min,因为分割的位置不能大于li的位置),li+1是位置0,因为5是最大的,但是此时li+1要和bi的位置取max(因为分割的位置不能小于bi的位置)

还需要特判第一个b的前面有没有比第一个b大的,最后一个b后面还有没有比最后一个b小的

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n,m;
    cin>>n>>m;

    vector<int> a(n+1),b(m+1);
    map<int,int> pos;

    for(int i=1;i<=n;i++){
        cin>>a[i];
        pos[a[i]]=i;
    }

    for(int i=1;i<=m;i++){
        cin>>b[i];
        b[i]=pos[b[i]];
    }

    vector<int> r(n+1,n+1),l(n+1,0);//r:右边最近的比他大的数的位置
    vector<int> stk;

    for(int i=n;i>=1;i--){
        while(stk.size() && a[stk.back()]<a[i]){
            stk.pop_back();
        }
        if(stk.size()){
            r[i]=stk.back();
        }
        stk.push_back(i);
    }

    stk.clear();

    for(int i=1;i<=n;i++){
        while(stk.size() && a[stk.back()]<a[i]){
            stk.pop_back();
        }
        if(stk.size()){
            l[i]=stk.back();
        }
        stk.push_back(i);
    }
    for(int i=1;i<=m;i++){
        if(i!=m) r[b[i]]=min(r[b[i]],b[i+1]);
        if(i!=1) l[b[i]]=max(l[b[i]],b[i-1]);
    }

    int ans=1;

    for(int i=1;i<m;i++){
        ans*=max(0ll,r[b[i]]-l[b[i+1]]);
        ans%=mod;
    }

    if(l[b[1]]!=0 || r[b[m]]!=n+1){
        ans=0;
    }

    cout<<ans<<endl;
}


signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}
posted @ 2025-06-23 02:57  LYET  阅读(21)  评论(0)    收藏  举报