牛客周赛 Round 95(A~F)

赛时没有Ak,今天做matlab作业做麻了

A.小红的数组查询(一)

思路:其实只和长度有关系,l==r,答案就为1,否则就为2

    #include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N=5e5+45;
const ll mod=998244353;
ll ksm(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans%mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
   ll l,r;
    // vector<ll>a(200,0);
    // a[1]=1;
    // for (ll i=3;i<=105;i++)a[i]=a[i-2];
    cin>>l>>r;
    if (l==r)cout<<1<<endl;
    else cout<<2<<endl;
}

B.小红的数组构造

思路:根据区间关系补差即可,除了第一个位置,\(b_i=a_i-a_{i-1}\)

    #include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N=5e5+45;
const ll mod=998244353;
ll ksm(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans%mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll n;
    cin>>n;
    vector<ll>a(n+5);
    for (ll i=1;i<=n;i++)cin>>a[i];
    ll q;
    cin>>q;
    while (q--) {
        ll l,r;
        cin>>l>>r;
        for (ll i=l;i<=r;i++) {
            if (i==l)cout<<a[i]<<" ";
            else cout<<a[i]-a[i-1]<<" ";
        }
        cout<<endl;
    }
}

C.小红的数组查询(二)

思路:我们发现其周期性出现,就是d加了很多次变成p的倍数了,那么周期长就是d和p的最小倍数/d,然后和区间长取个min即可

吐槽:赛时没看出p=1时特殊情况,直接走了(一直wa1个点没过,脑袋涨涨的,不想想了)

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N=5e5+45;
const ll mod=998244353;
ll ksm(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans%mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll d,p;
    cin>>d>>p;
    ll q;
    cin>>q;
    while (q--) {
        ll l,r;
        cin>>l>>r;
        if (p==1) {
            if (l==r)cout<<1<<endl;
            else if(l>=2)cout<<1<<endl;
            else cout<<2<<endl;
            continue;
        }
        //         if (p%d==0) {
        //             cout<<min(p/d,r-l+1)<<endl;
        //         }
        //         else {
        cout<<min(p/__gcd(p,d),r-l+1)<<endl;
        //         }
    }
}

D.小红的区间修改(一)

思路:如果在知道这个区间有没有数字>0,那么我们可以很快的解决这道问题。我们考虑用set修改区间下标即可,每次去修改区间有没有修改过,如果有,则跳过,否则暴力遍历,并修改答案

    #include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N=5e5+45;
const ll mod=998244353;
ll ksm(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans%mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
   ll q;
    cin>>q;
    vector<ll>a(350000,0);
    set<ll>k;
    ll ans=1;
    ll z=0;
    for (ll i=1;i<=q;i++) {
        ll l,r;
        cin>>l>>r;
        if (k.size()==0) {
            for (ll j=l;j<=r;j++) {
                k.insert(j);
            }
            ans+=r-l+1;
            z=r-l+1;
        }
        else {
            auto j=k.lower_bound(l);
            if (j==k.end()||(*j)>r) {
                for (ll j=l;j<=r;j++)k.insert(j);
                if (z<=r-l+1) {
                    ans+=r-l+1-z;
                    z=r-l+1;
                }
            }
        }
        cout<<ans<<endl;
    }

}

E.小红的数组操作

思路:答案无非就是只对左边,只对右边,和对左右进行覆盖或者不覆盖这四种情况取最优,那么这里给出一个通用方法,以一个循环作为左端点,然后单指针维护右端点,知道跳到加入个这个点时,数字出现次数大于等于2就不加了。此时只需单调维护cost(从现在往右覆盖)的最小值,也需要对于此时加入点右边的一个点取个min,然后对i所在位置取个左边覆盖值和i-1取个左边覆盖值最小,然后两者的加和取所有可能min即可得出答案

    #include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N=5e5+45;
const ll mod=998244353;
ll ksm(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans%mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll n;
    cin>>n;
    vector<ll>a(n+5,0);
    map<ll,ll>f2;
    ll ans=1e18;
    for (ll i=1;i<=n;i++)cin>>a[i];
    ll r=1;
    ll cost=1e18;
    for (ll i=1;i<=n;i++) {
        while (r!=n+1&&f2[a[r]]==0) {
            f2[a[r]]++;
            cost=min(cost,a[r]*(n-r+1));
            r++;
        }
        cost=min(cost,a[r]*(n-r+1));
        ans=min(ans,min(a[i]*i+cost,a[i-1]*(i-1)+cost));
        f2[a[i]]--;
    }
    cout<<ans<<endl;
}

F.小红的区间修改(二)

思路:打过今年郑州或者补过郑州C的人,应该一眼可以发现两个的覆盖模式很像,而且这个覆盖更简单(无需区间合并),所以直接暴力维护修改区间,并清除被覆盖区间和添加新区间,由于偷懒。毕竟牛客周赛不卡map,于是全用map+set写了。

赛时没看出来哪里错了,赛后一看=写出==了,改了就过了,QwQ

    #include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N=5e5+45;
const ll mod=998244353;
ll ksm(ll x,ll y) {
    ll ans=1;
    while (y) {
        if (y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans%mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll q;
    cin>>q;
    set<pair<ll,ll>>k;
    map<pair<ll,ll>,ll>f1;
    map<ll,ll>f2;
    ll ans=1;
    k.insert({1,100005});
    f2[0]=5000000;
    f1[{1,100005}]=0;
    while (q--) {
        ll l,r,d;
        cin>>l>>r>>d;
        ll c=l,e=r;
        vector<pair<ll,ll>>add,del;
        add.push_back({l,r});
        f2[d]++;
        if (f2[d]==1)ans++;
        while (1) {
            auto j=k.upper_bound({l,1e18});//第一个小于等于l的区间
            j--;
            auto [x,y]=(*j);
            del.push_back({x,y});
            f2[f1[{x,y}]]--;
            ll xx=f1[{x,y}];
            if (f2[xx]==0)ans--;
            if (x!=l)
            {
                add.push_back({x,l-1});
                f1[{x,l-1}]=xx;
                f2[xx]++;
                if (f2[xx]==1)ans++;
            }
            if (r<y) {
                add.push_back({r+1,y});
                f1[{r+1,y}]=xx;
                f2[xx]++;
                if (f2[xx]==1)ans++;
            }
            l=y+1;
            if (l>r)break;
        }
        for (auto [x,y]:del)k.erase({x,y});
        for (auto [x,y]:add)k.insert({x,y});
        del.clear(),add.clear();
        f1[{c,e}]=d;
        cout<<ans<<endl;
    }
}
posted @ 2025-06-08 21:41  长皆  阅读(66)  评论(0)    收藏  举报