yuwj  

写在前面

打这场之前上了一节基础课,一个sb题,我WA了一发,然后罚时最后倒二hhh,

发现自己状态严重不对,所以这场就没打了,

早上 vp 的,rk4100+,E 思路对了,就是写不对,哎哎哎,太菜

果然连续 3 天没怎么睡觉身体还是撑不住了

A

直接枚举每个子数组即可

void Solve(){
    cin >> n;
    vector<int> num(n+1);
    For(i,1,n) cin >> num[i];

    int ans = 0;
    For(i,1,n){
        int tmp = 0;
        For(j,i,n){
            tmp += num[j];
            int avg = tmp/(j-i+1);
            ans = max(ans,avg);
        }
    }

    cout << ans << '\n';
}

B

把 0 全删了就行

void Solve(){
    cin >> n >> s;
    cout << count(all(s),'0') << '\n';
    for(int i=0;i<n;++i){
        if(s[i]=='0') cout << i + 1<< ' ';
    }cout<<'\n';
}

C

注意到 msb(a) < msb(b),无解,否则,先将 a0 b1 的地方加上,再将 a1 b0 的地方减掉就行了

操作最多两次

void Solve(){
    int a,b;
    cin >> a >> b;
    if(__lg(a) < __lg(b)) {
        cout << "-1\n";
        return;
    }

    if(a==b) {cout<<"0\n";}
    else{
        int A = 0, B = 0;
        for(int i = __lg(a); i>=0; --i){
            int u = (a>>i & 1), v = (b>>i & 1);
            // cerr << u << ' ' << v << '\n';
            if(u == 0 && v == 1) A += (1ll << i);
            if(u == 1 && v == 0) B += (1ll << i);
        }
        // cerr << A << ' ' << B << '\n';
        int ans = (A>0) + (B>0);
        cout<<ans<<'\n';
        if(A) cout << A << ' ';
        if(B) cout << B;
        cout<<'\n';
    }
}

D

考虑分治,从中点往两边查询端点,如果 sum1 < sum2,则有可能存在端点,否则不可能

以左端点为例,只要一直往左走,不能走了往右走,到了一个点就返回了,需要查两次,右端点类似

但是这样查两端的次数是 4*15 = 60 次,发现操作是区间每个数字 +1, 则区间长度就是 和的差值,即 len = tot2 - tot1

所以只要找一个点就能一次查询长度得到另一个点,次数最多 30,结束

int ask(int op, int l, int r){
    cout << op <<" " << l << ' ' << r <<endl;
    int res;cin >> res;
    return res;
}

void answer(int l,int r){
    cout << "! " << l << ' ' << r << endl;
}

int work(int l,int r){
    if(l == r) return l;
    
    int mid = l+r >> 1;
    int res1 = ask(1,l,mid), res2 = ask(2,l,mid);
    if(res1 < res2){
        return work(l,mid);
    }else return work(mid+1,r);
}

// 1.区间+1,长度可知,
// 2.只要一个点就好了
void Solve(){
    cin >> n;
    int sum = ask(2,1,n), len = sum - n*(n+1)/2;
    int l = work(1,n), r = l + len - 1;
    answer(l,r);
}

E

发现只要让新增加的数字与前两个数字不等就能保证回文,但是第一个数字要特判掉

发现,由于 x 的取值最多为 n,而回文数组又一定有某些数字无法出现,否则无法形成回文,例如排列

那么,第一个数字直接取值为第一个未出现的数字就肯定不会形成回文(每个数字都能作为回文对称点,所以 a1 ~ an 都有可能),如果都出现了,选 1 就行

然后构造剩下的 k-1 个,其实只要 1 2 3 三个数字即可,保证与前两个数字不等,可以边枚举边维护前两个点就完了

// 1. 只要与前两个不同即可
// 2. 第一个数字直接选没有出现的数字,否则只要 1 2 3 就行了
void Solve(){
    cin >> n >> k;
    set<int> st;
    For(i,1,n) st.insert(i);
    vector<int> num(n+1);
    For(i,1,n) cin >> num[i], st.erase(num[i]);
    
    int a = num.back(), b = num[n-1];
    if(a == b) b = num[n-2];
    int c;
    if(st.size()){
        c = *st.begin();
    }else{
        c = 1;
        while(a == c || b == c) ++c;
    }
    cout << c << ' ';
    num.pb(c);

    for(int i=1;i<k;++i){
        int a = num.back(), b = num[(int)num.size()-2];
        int c = 1;
        while (c==a || c==b) ++c;
        cout << c << ' ';
        num.pb(c);
    }

    cout << '\n';
}
posted on 2025-10-18 11:08  xiaowang524  阅读(14)  评论(0)    收藏  举报