Codeforces Round 900 (Div. 3)

Codeforces Round 900 (Div. 3) DEF

D. Reverse Madness?

原题链接
Problem Statement

You are given a string \(s\) of length \(n\), containing lowercase Latin letters.

Next you will be given a positive integer \(k\) and two arrays, \(l\) and \(r\) of length \(k\).

It is guaranteed that the following conditions hold for these 2 arrays:

  • \(l_1 = 1\);
  • \(r_k = n\);
  • \(l_i \le r_i\), for each positive integer \(i\) such that \(1 \le i \le k\);
  • \(l_i = r_{i-1}+1\), for each positive integer \(i\) such that \(2 \le i \le k\);

Now you will be given a positive integer \(q\) which represents the number of modifications you need to do on \(s\).

Each modification is defined with one positive integer \(x\):

  • Find an index \(i\) such that \(l_i \le x \le r_i\) (notice that such \(i\) is unique).
  • Let \(a=\min(x, r_i+l_i-x)\) and let \(b=\max(x, r_i+l_i-x)\).
  • Reverse the substring of \(s\) from index \(a\) to index \(b\).

Reversing the substring \([a, b]\) of a string \(s\) means to make \(s\) equal to \(s_1, s_2, \dots, s_{a-1},\ s_b, s_{b-1}, \dots, s_{a+1}, s_a,\ s_{b+1}, s_{b+2}, \dots, s_{n-1}, s_n\).

Print \(s\) after the last modification is finished.

解题思路

二分查找每一个x对应的下标i,记录L = min( l + r - x ,x ),R = max( l + r - x ,x ),观察到每一个翻转都是独立在不同区间的,即不存在两个相交的翻转,那么考虑记录1到n每一个点翻转次数,奇数次翻转,偶数次不翻转,翻转次数可以考虑差分记录a[L]--,a[R+1]++,然后进行一次前缀和还原。

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll inf=1e18;
void solve(){
    int n,k;string s;cin>>n>>k>>s;
    vector<int>a(n+2);
    vector<char>f(n+1);
    vector<int>_l(k+1),_r(k+1);
    for(int i=1;i<=k;i++) cin>>_l[i];
    for(int i=1;i<=k;i++) cin>>_r[i];
    int m;cin>>m;
    for(int i=1,_x;i<=m;i++) {
        cin>>_x;
        int ls=1,rs=k;
        while(ls<=rs){
            int mid=ls+rs>>1;
            if(_l[mid]<=_x) ls=mid+1;
            else rs=mid-1;
        }
        int L=min(_l[ls-1]+_r[ls-1]-_x,_x),R=max(_l[ls-1]+_r[ls-1]-_x,_x);
        a[L]++,a[R+1]--;
    }
    for(int i=1;i<=n;i++) a[i]+=a[i-1];
    int tx=0;
    for(int i=1;i<=n;i++){
        if(a[i]&1LL){
            if(f[i]) continue;
            int ls=1,rs=k;
            while(ls<=rs){
                int mid=ls+rs>>1;
                if(_l[mid]<=i) ls=mid+1;
                else rs=mid-1;
            }
            int len=(_r[ls-1]+_l[ls-1]);
            int ri=(len-i);
            swap(s[i-1],s[ri-1]);
            f[ri]=1;
        }
    }
    cout<<s<<endl;
}   
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T=1;cin>>T;
    while(T--) solve();
    return 0;
}

E. Iva & Pav

原题链接
Problem Statement

Iva and Pav are a famous Serbian competitive programming couple. In Serbia, they call Pav "papuca" and that's why he will make all of Iva's wishes come true.

Iva gave Pav an array \(a\) of \(n\) elements.

Let's define \(f(l, r) = a_l \ \& \ a_{l+1} \ \& \dots \& \ a_r\) (here \(\&\) denotes the bitwise AND operation).

Note that \(f(l, r)\) is not defined when \(l > r\).

Iva also gave Pav \(q\) queries.

Each query consists of 2 numbers, \(k\) and \(l\), and she wants Pav to find the largest index \(r\) (\(l \le r \le n\)), such that \(f(l, r) \ge k\).

Pav wants to solve this problem fast because he doesn't want to upset Iva. He needs your help.

解题思路

简要概括一下题意,给定一个序列,给你q组询问,每组询问丢给你左端点l和一个值k,要你求最大的r满足在这个序列中,从l到r连续按位与之后大于等于k
一个比较显然的思路是二分,因为肯定存在某一位k是恰好满足,而k+1不满足,这很单调,
又因为这是位运算,所以拆位考虑。对每一位i单独考虑,想要在当前位连续未与操作出1,当且仅当这一位在l到r上都是1,那我可以用一个前缀数组pre记录从1到这一位上1的个数,当\(pre[r]-pre[l-1]=r-l+1\)时,对结果产生2i的价值。

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll inf=1e18;
void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    vector f(n+1,vector<int>(31));
    for(int i=1;i<=n;i++){
        for(int j=0;j<31;j++){
            if(a[i]>>j&1) f[i][j]++;
        }
    }
    for(int i=1;i<=n;i++) for(int j=0;j<31;j++) f[i][j]+=f[i-1][j];
    int q;cin>>q;
    auto isok=[&](int l,int mid,ll k)->bool{
        vector<int>bit(31);
        for(int j=0;j<31;j++) bit[j]=f[mid][j]-f[l-1][j];
        ll ans=0;
        for(int j=0;j<31;j++) if(bit[j]==mid-l+1) ans+=(1LL<<j);
        return ans>=k;
    };
    for(int i=1;i<=q;i++){
        int l;ll k;cin>>l>>k;
        if(a[l]<k) {cout<<-1<<' ';continue;}
        int ls=l,rs=n;
        while(ls<=rs){
            int mid=ls+rs>>1;
            if(isok(l,mid,k)) ls=mid+1;
            else rs=mid-1;
        }
        cout<<rs<<' ';
    }
    cout<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T=1;cin>>T;
    while(T--) solve();
    return 0;
}

解题思路2

想要找到最大满足的r,考虑用一种数据结构进行维护,存储l到r连续位与的值,
因为对某一位进行重复位与操作不会影响实际的结果,所以可以直接用st表记录从l到r位置连续位与的值
查询时从x初始化为231-1,从高位开始贪心的查询,在满足当前i>=l&&i+(1<<len)-1<=r的情况下尽可能跳到较高的位置,x同时位与st表的值。

AC code2

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll inf=1e18;
void solve(){
    int n;cin>>n;
    vector a(20,vector<int>(n+1));
    for(int i=1;i<=n;i++) cin>>a[0][i];
    int len=__lg(n);
    for(int i=1;i<=len;i++){
        for(int j=1;j<=n-(1<<i)+1;j++){
            a[i][j]=a[i-1][j]&a[i-1][j+(1<<i-1)];
        }
    }
    auto query=[&](int l,int k){
        int r=l,x=((1LL<<31)-1);
        for(int i=__lg(n);~i;i--){
            if(r+(1LL<<i)-1<=n&&(x&a[i][r])>=k) x&=a[i][r],r+=(1LL<<i);
        }
        cout<<r-1<<' ';
    };
    int q;cin>>q;
    for(int i=1,l,k;i<=q;i++){
        cin>>l>>k;
        if(a[0][l]<k) {cout<<-1<<" ";continue;}
        query(l,k);
    }
    cout<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T=1;cin>>T;
    while(T--) solve();
    return 0;
}

F. Vasilije Loves Number Theory

原题链接

Problem Statement

Vasilije is a smart student and his discrete mathematics teacher Sonja taught him number theory very well.

He gave Ognjen a positive integer \(n\).

Denote \(d(n)\) as the number of positive integer divisors of \(n\), and denote \(gcd(a, b)\) as the largest integer \(g\) such that \(a\) is divisible by \(g\) and \(b\) is divisible by \(g\).

After that, he gave Ognjen \(q\) queries, and there are \(2\) types of queries.

  • \(1\), \(x\) — set \(n\) to \(n \cdot x\), and then answer the following question: does there exist a positive integer \(a\) such that \(gcd(a, n) = 1\), and \(d(n \cdot a) = n\)?
  • \(2\) — reset \(n\) to its initial value (before any queries).

Note that \(n\) does not get back to its initial value after the type 1 query.

Since Ognjen is afraid of number theory, Vasilije promised him that after each query, \(d(n) \le 10^9\), however, even with that constraint, he still needs your help with this problem.

解题思路

根据质因数唯一分解定理,,作\(f(x,p)\)为对 x 来说每个因子p出现的最大次数,则有 $d(n)=\prod_{n|p,p \in prime }^n f(n,p)+1 $ ,因为\(gcd(a,n)=1\),所以不存在一个质数p使得\(f(a,p) \neq 0\)时,\(f(n,p) \neq 0\)
所以当且仅当 \(d(n·a)=d(n)·d(a)\) ,即 \(n=d(n)·d(a)\)时是YES,需要维护的数即\(n\)\(d(n)\),判断 \(d(n)|n\) 是否成立即可,考虑存储每个因子,利用快速幂和简单循环还原出 $d(n)=\prod_{n|p,p \in prime }^n f(n,p)+1 $ 和 $n=\prod_{n|p,p \in prime }^n $pf(n,p) 即可.

AC code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll inf=1e18;
ll q_pow(ll a,ll b,ll mod){
    ll s=1;
    while(b){
        if(b&1){
            s=s*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return s;
}
void solve(){
    ll n;int q;cin>>n>>q;
    map<int,int>mp,premp;
    for(int i=2;i<=sqrtl(n);i++){
        while(n%i==0){ n/=i;++mp[i];} 
    }
    if(n>1) ++mp[n];
    premp=mp;
    for(int i=1,op;i<=q;i++){
        cin>>op;
        if(op==1){
            int x;cin>>x;
            for(int i=2;i<=sqrtl(x);i++){
                while(x%i==0) x/=i,++mp[i];
            }
            if(x>1) ++mp[x];
            ll ans=1,nx=1;
            for(auto &[a,b]:mp) ans=ans*(b+1LL);
            for(auto &[a,b]:mp) nx=nx*q_pow(a,b,ans)%ans;
            if(nx%ans) cout<<"NO"<<endl;
            else cout<<"YES"<<endl;
        }
        else if(op==2) mp=premp;
    }
    cout<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T=1;cin>>T;
    while(T--) solve();
    return 0;
}
posted @ 2025-04-23 21:04  usedchang  阅读(18)  评论(0)    收藏  举报