2026牛客寒假算法基础集训营1 9/12

L. Need Zero

点击查看代码
#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;

    for(int i=1;i<=n;i++){
        if((n*i)%10 == 0){
            cout<<i<<endl;
            return;
        }
    }
}

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

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

K. Constructive

只有 \(n=1\)\(n=3\) 时,有解,更大的 \(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;

    if(n==1){
        cout<<"YES\n1\n";
    }
    else if(n==3){
        cout<<"YES\n1 2 3\n";
    }
    else{
        cout<<"NO\n";
    }
}

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

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

C. Array Covering

显然,可以把 \([2,n-1]\) 中的所有数都变成整个序列的最大值

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long; 
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;

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

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

    int mx=*max_element(a.begin()+1,a.end());
    for(int i=2;i<n;i++){
        a[i]=mx;
    }

    cout<<accumulate(a.begin()+1,a.end(),0ll)<<endl;
}

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

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

    return 0;
}

E. Block Game

等价于把万能方块放到 \(a[n+1]\) 的位置。

然后找两个相邻位置和的最大值即可,注意 \(i=1\)\(i=n+1\) 也算是相邻

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long; 
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;

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

    vector<int> a(n+1);

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

    int ans=max(a[1]+k,a[n]+k);

    for(int i=2;i<=n;i++){
        ans=max(ans,a[i-1]+a[i]);
    }

    cout<<ans<<endl;
}

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

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

    return 0;
}

B. Card Game

找到 \(b\) 数组的最大值 \(mn\),显然,\(a\) 数组中的所有比 \(mn\) 大的数字,都可以被消除,而所有比 \(mn\) 小的数字,都不能被消除

所以,把所有比 \(mn\) 大的数字放在前面,小的数字放到后面即可。

点击查看代码
#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;

    vector<int> a(n+1),b(n+1),fact(n+1);
    fact[0]=1;

    for(int i=1;i<=n;i++){
        cin>>a[i];
        fact[i]=fact[i-1]*i%mod;
    }
    for(int i=1;i<=n;i++){
        cin>>b[i];
    }
    
    int mn=*min_element(b.begin()+1,b.end());
    int cnt=0;

    for(int i=1;i<=n;i++){
        if(a[i]>mn) cnt++;
    }

    cout<<fact[cnt]*fact[n-cnt]%mod<<endl;

}

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

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

G. Digital Folding

\(l=r\) 时,答案固定

\(l\) 的位数,比 \(r\) 的位数小时:

如果 \(r=1000..00\) 这样的,答案一定是 \(99..99\),长度是 \(r\) 的位数 -1

否则,答案的长度一定是 \(r\) 的位数

所以,可以在此时,把 \(l\) 设置为 \(100.00\),长度为 \(r\) 的位数

此时, \(l,r\) 的位数一定相等。

注意,现在还没有进行反转,所以要要尽可能让靠后的位的数值变大

从前往后循环,\(l,r\) 前面完全相同的位是动不了的,知道某一个位不同,就可以让这一位的数值 -1,然后让后面的位都变成 \(9\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long; 
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;

int len(int x){
    int res=0;
    while(x){
        x/=10;
        res++;
    }
    return res;
}

string rv(int x){
    string t;
    while(x){
        int val=x%10;
        t.push_back((char)val+'0');
        x/=10;
    }
    return t;
}

string str(int x){
    auto s=rv(x);
    reverse(s.begin(),s.end());
    return s;
}

void solve(){
    int l,r;
    cin>>l>>r;

    if(l==r){
        string s=rv(l);
        int p=0;
        for(int i=0;i<s.size();i++){
            if(s[i]!='0'){
                p=i;
                break;
            }
        }
        for(int i=p;i<s.size();i++){
            cout<<s[i];
        }
        cout<<endl;
        return;
    }

    if(len(l)!=len(r)){
        if(len(r)!=len(r-1)){
            for(int i=1;i<=len(r-1);i++){
                cout<<9;
            }
            cout<<endl;
            return;
        }
        else{
            l=1;
            for(int i=1;i<len(r);i++){
                l*=10;
            }
        }
    }

    string a=str(l),b=str(r);

    //现在答案的长度已经固定了
    int pos=-1,f=0,nd=0;
    string ans;

    for(int i=0;i<a.size();i++){
        if(f && b[i]<'9'){
            ans.push_back('9');
            nd=1;
            continue;
        }
        if(a[i]==b[i]){
            ans.push_back(a[i]);
        }
        else{
            if(pos==-1){
                pos=i;
                f=1;
            }
            ans.push_back(b[i]);
        }
    }

    if(nd) ans[pos]--;
    reverse(ans.begin(),ans.end());

    cout<<ans<<endl;
}

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

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

    return 0;
}

H. Blackboard

核心性质:如果两个数与运算结果为零,则或运算和加法的结果相同。

否则,或运算的结果一定比加法小,原因是或运算没有进位

\(f[i]\) 表示,只考虑前 \(i\) 个数有多少种合法的情况

对于每一个 \(i\),枚举可以进行多少次连续的或运算,即可以连续或上前面多少个数,满足或运算和加法结果一样。

最多 \(32\) 个正整数。因为只有 \(32\) 位,所以或上 \(32\) 个数后,一定有一位的 \(1\) 会重复

因为数组中有 \(0\),所以需要预处理出来,每个数前面最近的正整数在哪里

对于 \(f[i]\),如果前面最长可以或上位置 \(pos+1\),则 \(f[i]\) 等于 \(pref[i-1]-pref[pos-1]\),即 \(f[i-1]\)\(f[pos]\) 的和

(等价于枚举,往前连续的或运算后,第一个加法前的位置,而这个位置的答案就是 \(f[j]\))

其中,\(pref\)\(f\) 的前缀和数组

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

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

    vector<int> a(n+1);
    vector<int> lst(n+1);
    int now=0;

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

    vector<int> f(n+1),s(n+1);
    f[0]=1,s[0]=1;

    for(int i=1;i<=n;i++){
        int now=i,val=0;
        while(now && (val&a[now])==0){
            val|=a[now];
            now=lst[now];
        }

        if(now==0) f[i]=s[i-1];
        else f[i]=(s[i-1]-s[now-1]+mod)%mod;

        s[i]=(f[i]+s[i-1])%mod;
    }

    cout<<f[n]<<endl;
}

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

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

    return 0;
}

D. Sequence Coloring

二分,懒得写了

I. AND vs MEX

如果 \(l=0\),则答案就是 \(r+1\)

\(l,r\) 的最高位 \(1\) 的位置分别为 \(b1,b2\)

如果 \(b1=b2\),则无论如何都搞不出 \(0\),答案为 \(0\)

如果 \(b1+1<b2\) 则可以使用 \((1<<b2)-1\) 和其他数,容易的把 \(0-(l-1)\) 与出来

如果 \(b1+1=b2\):

\(x~=~(1<<b2)-1\),让 \(x\) 异或 \(x+1,x+2,...,r\),可以得到 \(0,1,...,r-x-1\),则此时第一个与不出来的数为 \(r-x\)

如果 \(r-x>=l\),则答案为 \(r+1\)

刚刚是从 \(x\) 往上异或,接下来从 \(x\) 往下异或,注意可以异或多个数。找到 \(l\) 中最高的和 \(x\) 不同的位,从这一位开始都可以是 \(0\)

比较这两个数,判断答案是 \(r+1\) 还是 \(r-x\)

posted @ 2026-03-11 17:43  LYET  阅读(14)  评论(0)    收藏  举报