cf984(div3)(A-G)

要复健了:(

A

void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    rep(i,1,n){
        cin>>a[i];
    }
    rep(i,2,n){
        if(abs(a[i]-a[i-1])!=5&&abs(a[i]-a[i-1])!=7){
            cout<<"NO"<<endl;return;
        }
    }
    cout<<"YES"<<endl;
}

B

模拟+贪心,看哪一个品类的商品总价值最高就先卖哪一类

void solve(){
    int n,k;cin>>n>>k;
    map<int,int>tot;
    rep(i,1,k){
        int b,c;cin>>b>>c;
        tot[b]+=c;
    }
    priority_queue<int>q;
    for(auto[x,y]:tot){ 
        q.push(y);
    }
    int ans=0;
    while(n&&q.size()){
        ans+=q.top();
        q.pop();
        n--;
    }
    cout<<ans<<endl;
}

C

题意:

给定一个01字符串以及q次查询,每次查询修改字符串一个位置的字符,求每次查询过后字符串是否存在1100子串

思路:

先计算原本的字符串的1100子串数目
每次查询中,如果修改后的字符与原字符相同,则相当于没修改
反之,需要观察这个字符影响的答案,即它会影响从max(1,i-3)~min(n-3,i)开头的长度为4的字符串
暴力判断即可

void solve(){
    string s;cin>>s;
    int n=s.size();
    s=" "+s;
    int cnt=0;
    rep(i,1,n-3){
        if(s.substr(i,4)=="1100"){
            cnt++;
        }
    }
    int q;cin>>q;
    while(q--){
        int i;cin>>i;char ch;cin>>ch;
        if(s[i]!=ch){
        for(int j=max(1,i-3);j<=min(n-3,i);j++){
            if(s.substr(j,4)=="1100"){
                cnt--;
            }
        }
        s[i]=ch;
        for(int j=max(1,i-3);j<=min(n-3,i);j++){
            if(s.substr(j,4)=="1100"){
                cnt++;
            }
        }
        }
        
        if(cnt>0){
            cout<<"YES"<<endl;
        }else cout<<"NO"<<endl;
    }
}

D

题意:

给定一个nxm的数字矩阵,其中n和m都是偶数,求min(n,m)/2个绕着矩阵中心的大环上有多少个1543

思路:

需要暴力模拟
先看如何把矩阵的一个环给扯下来
显然如果是第i个环,那么
第i行:[i,m-i+1]列
第m-i+1列:[i+1,n-i+1]行
第n行:[m-i,i]列
第i列:[n-i,i+1]行
把环上的数字取下来放到数组里,然后取模判断1543的数量
环的数量为min(n,m)/2

char g[1005][1005];
int check(vector<char>&v){
    int k=v.size();
    int res=0;
    for(int j=0;j<k;j++){
        if(v[j]=='1'&&v[(j+1)%k]=='5'&&v[(j+2)%k]=='4'&&v[(j+3)%k]=='3')res++;
    }
    return res;
}
void solve(){
    int n,m;cin>>n>>m;
    rep(i,1,n){
        string s;cin>>s;s=" "+s;
        rep(j,1,m){
            g[i][j]=s[j];
        }
    }
    int ans=0;
    for(int i=1;i<=min(n,m)/2;i++){
        vector<char>v;
        for(int j=i;j<=m+1-i;j++)v.pb(g[i][j]);
        for(int j=i+1;j<=n+1-i;j++)v.pb(g[j][m+1-i]);
        for(int j=m-i;j>=i;j--)v.pb(g[n-i+1][j]);
        for(int j=n-i;j>=i+1;j--)v.pb(g[j][i]);
        ans+=check(v);
    }
    cout<<ans<<endl;
}

E

题意:

给定一个nxk的矩阵,矩阵的每一列从第一行到第n行,变换为x|pre(x为所处位置的矩阵值,pre为上面行的矩阵按位或值)
给出m个条件限制每一列的大小,需要输出满足条件的最小行的编号

思路:

显然通过按位或操作后的矩阵,下面行的值一定大于等于上面行的值
每一列都满足从上至下单调递增,所以可以二分
划定满足答案的编号范围为l~r,初始l=1,r=n
对于每一个条件,二分调整l或r的大小
如果最后l>r那么无解

void solve(){
    int n,k,q;cin>>n>>k>>q;
    vector<vector<int>>g(n+1,vector<int>(k+1));
    rep(i,1,n){
        rep(j,1,k){
            cin>>g[i][j];
        }
    }
    for(int j=1;j<=k;j++){
        int pre=0;
        for(int i=1;i<=n;i++){
            pre|=g[i][j];
            g[i][j]=pre;
        }
    }

    while(q--){
        int m;cin>>m;
        int l=1,r=n;
        int f=1;
        rep(i,1,m){
            int rt,c;char o;
            cin>>rt>>o>>c;
            //g[1~n][r]
            if(o=='>'){
                int li=l,ri=r;
                int ok=0;
                while(li<=ri){
                    int mid=li+ri>>1;
                    if(g[mid][rt]>c){
                        l=mid;
                        ok=1;
                        ri=mid-1;
                    }else li=mid+1;
                }
                if(!ok)f=0;
            }else if(o=='<'){
                int li=l,ri=r;
                int ok=0;
                while(li<=ri){
                    int mid=li+ri>>1;
                    if(g[mid][rt]<c){
                        r=mid;
                        ok=1;
                        li=mid+1;
                    }else ri=mid-1;
                }
                if(!ok)f=0;
            }
        }
        if(l<=r&&f){
            cout<<l<<endl;
        }else cout<<-1<<endl;
    }
}

F

题意:

给定q个查询,每次查询l~r范围的数的异或和,刨除掉其中与k同模(2^i)的数x的异或值

思路:

神秘结论
f60cbedd74d196472de82eba6ca719d4

那么l~r的异或值即f(r)^f(l-1)
现在考虑如何x的异或和
令x=k+j*2^i(j>=0)

由于l<=x<=r
有(l-k)<<i <= j <= (r-k)<<i
按位考虑
由于k是小于2^i的
所以k的二进制最高位是小于i的
[1,i-1]上只有k的二进制位,答案是否异或k取决于x的个数奇偶性
x的个数取决于j的个数,且x的[i,64)的二进制位异或为 xor(j,j+1,j+2,...)<<i
注意右边界小于0时,x的个数为0

int f(int x){
    if(x%4==1){
        return 1;
    }else if(x%4==2){
        return x+1;
    }else if(x%4==3){
        return 0;
    }else{
        return x;
    }
}
void solve(){
    int q;cin>>q;
    while(q--){
        int l,r,i,k;cin>>l>>r>>i>>k;
        int ans=f(r)^f(l-1);
        if(r<k){
            cout<<ans<<endl;continue;
        }
        int left=(l-k-1>>i)+1;
        int right=(r-k)>>i;
        if(left<0)left=0;
        if((right-left+1)&1)ans^=k;
        ans^=((f(right)^f(max(0ll,left-1)))<<i);
        cout<<ans<<endl;
    }

}

G

题意:

交互题,有n种书,每种书两本,现在有三种各缺失了一本
每次可以查询[l,r]范围的书的编号(如果某种书有两本,则抵消)的异或值,求出三本缺失的书的编号

思路:

设答案书的编号为 a<b<c,
当xor[1,n]不为0时,可以利用单调性二分求出a和c(因为a xor b 和 b xor c一定不为0):
显然xor[1,a-1]=0,xor[1,a]=a
xor[c+1,n]=0,xor[c,n]=c
b=xor[1,n]^a^c
当xor[1,n]为0时,没有单调性,因为当区域xor为0时无法判断是[1,a-1]还是[1,c]
当三个数的异或值为0时,说明每一位的1的个数为偶数
发现b的最高位1一定不用于a的最高位1
所以可以枚举[1,2^i-1],当xor不等于0时,此时一定为a
然后b,c的范围为[2^i,n]
因为 b xor c一定不为0,所以可以再次利用二分求出b

void solve(){
    int n;cin>>n;
    cout<<"xor "<<1<<' '<<n<<endl;
    cout.flush();
    int xt;cin>>xt;

    if(xt!=0){
        int a=0,b=0,c=0;
        int l=1,r=n;
        while(l<=r){
            int mid=l+r>>1;
            cout<<"xor "<<1<<' '<<mid<<endl;cout.flush();
            int x;cin>>x;
            if(x==0){
                l=mid+1;
            }else{
                a=mid;
                r=mid-1;
            }
        }
        l=1,r=n;
        while(l<=r){
            int mid=l+r>>1;
            cout<<"xor "<<mid<<' '<<n<<endl;cout.flush();
            int x;cin>>x;
            if(x==0){
                r=mid-1;
            }else{
                c=mid;
                l=mid+1;
            }
        }
        cout<<"ans "<<a<<' '<<(xt^a^c)<<' '<<c<<endl;
        cout.flush();
        return;
    }
   

    int a=0,b=0,c=0;
    int l=1,r=n;
    for(int i=1;i<64;i++){
        if((1ull<<i)>n)break;
        
        cout<<"xor "<<1<<' '<<((1ull<<i)-1)<<endl;cout.flush();
        int x;cin>>x;
        if(x!=0){
            a=x;
            l=(1ull<<i);
            break;
        }
    }
    int li=l;
    while(l<=r){
        int mid=l+r>>1;
        cout<<"xor "<<li<<' '<<mid<<endl;cout.flush();
        int x;cin>>x;
        if(x!=0){
            b=x;
            r=mid-1;
        }else{
            l=mid+1;
        }
    }
    cout<<"ans "<<a<<' '<<b<<' '<<(a^b)<<endl;
    cout.flush();
}
posted @ 2025-07-14 21:42  Marinaco  阅读(8)  评论(0)    收藏  举报
//雪花飘落效果