T3 玄泡麵求調

Aqr_Rn發表於2024-10-05

覺得模擬賽題解還是單獨放出來比較好。

A.擠壓

好像不難?二進位制表示下的平方展開沒推出來,不然就成簡單題了。

首先我們需要知道對於一個數 \(x\),把它拆成 29 位的二進位制形式後,用 \(s_i\) 表示二進位制下第 \(i\) 位上的數,那麼其實這個數就是 \((\overline{s_{29} s_{28}...s_1 s_0})_2\),那麼有

\[\begin{aligned} (\overline{s_{29} s_{28}...s_1 s_0})^2&=(\sum_{i=0}^{29} s_i\times 2^i)^2 \\ &=\sum_{i,j\in [0,29]} 2^{i+j} (if\ s_i=1\ and\ s_j=1)\end{aligned}\]

那麼可以知道只有二進位制下兩位數同時為 1 時才會對答案有貢獻,這樣我們就可以列舉二進位制下的兩位 \(i,j\),在此基礎上迴圈整個序列設 \(f_{k,0/1,0/1}\) 表示前 \(k\) 個數的第 \(i,j\) 位選了奇/偶個的機率,最後計算上 \(f_{n,1,1}\) 對答案的貢獻即可。

注意第 \(k\) 個數選或不選的轉移有以下幾種情況:

  • 二進位制下的這個數第 \(i,j\) 位都不為 1,那麼顯然它對答案,直接繼承就行;

  • \(i\) 位為 1 而 第 \(j\) 位不為 1,那麼若選這個數,則只有第 \(i\) 位的奇偶發生變化;反之同理;

  • \(i,j\) 位都為 1,選這個數時,\(i,j\) 兩位上的奇偶都發生變化,以此為例:

\[\begin{aligned}f_{k,x,y} &=f_{k-1,x\oplus 1,y\oplus 1}\times p_k (選這個數的機率) \\ &+f_{k-1,x,y}\times q_k(不選這個數的機率) \end{aligned}\]

對於每一組 \(i,j\),初始化 \(f_{0,0,0}=0\) 即可。

B.工地難題

字首和最佳化:設 \(f_i\) 表示最長連續 1 的個數 \(num\le i\) 的方案數,顯然對於最長連續 1 的個數恰好等於 \(i\) 的答案就是 \(f_i-f_{i-1}\)

現在我們考慮如何求 \(f_i\)。我們可以將題目理解為插板的形式:放好了 \(n-m\) 個 0,那麼現在有 \(n-m+1\) 個位置可以插入 1,每個位置上都可以放 \([0,m]\) 個 1,問方案數。

\(x_j\) 表示第 \(j\) 個位置放了幾個 1,那麼求 \(f_i\) 其實就是求 \(\sum_{j=1}^{n-m+1} x_j=m\) 的非負整數解的個數。簡單容斥一下就好了。

C.星空遺蹟

求調!!!

T3 求調,**12:00 之前調成功懸一袋紅燒牛肉麵 **

#include<bits/stdc++.h>
#define Type int
#define qr(x) x=read()
typedef long long ll;
using namespace std;

inline Type read(){
    char c=getchar(); Type x=0;
    while(!isdigit(c))c=getchar();
    while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}

const int N = 2e5 + 10;
const int mod = 1e9 + 7;

int n, q, f[N];
char s[N];

int P(char A, char B){
    if(A == '#' or B == '@') return 1;
    if(A == B) return 0;
    if(A == 'R'){
        if(B == 'S') return 1;
        else return -1;
    }
    else if(A == 'S'){
        if(B == 'P') return 1;
        else return -1;
    }
    else{
        if(B == 'R') return 1;
        else return -1;
    }
}
struct tree{
        int v, pos, tag;

        bool operator < (const tree &A) const{
            return v < A.v;
        }
    }t[N<<3];
namespace Tree
{
    #define lson rt<<1
    #define rson rt<<1|1
    
    inline void pushup(int rt){
        if(t[lson].v < t[rson].v) t[rt].v = t[lson].v, t[rt].pos = t[lson].pos;
        else t[rt].v = t[rson].v, t[rt].pos = t[rson].pos;
    }

    inline void pushdown(int rt){
        if(t[rt].tag){
            t[lson].tag += t[rt].tag, t[rson].tag += t[rt].tag;
            t[lson].v += t[rt].tag, t[rson].v += t[rt].tag;
            t[rt].tag = 0;
        }
    }

    inline void build(int rt, int l, int r){
        if(l == r){
            t[rt].v = f[l], t[rt].pos = l;
            return;
        }

        int mid = (l + r) >> 1;
        build(lson, l, mid),
        build(rson, mid+1, r);
        
        pushup(rt);

        // if(t[rt].pos == 0) cout<<"CTHisSB\n";
    }

    inline void update(int rt, int l, int r, int pos, int val){
        if(pos <= l and r <= n){
            t[rt].tag += val, t[rt].v += val;
            return;
        }pushdown(rt);

        int mid = (l + r) >> 1;
        if(pos <= mid) update(lson, l, mid, pos, val);
        if(n > mid) update(rson, mid+1, r, pos, val);

        pushup(rt);
    }

    inline tree query(int rt, int l, int r, int L, int R){
        if(L <= l and r <= R) return t[rt];
        pushdown(rt); 

        int mid = (l + r) >> 1;

        if(R <= mid) return query(lson, l, mid, L, R);
        else{
            if(L > mid) return query(rson, mid+1, r, L, R);
            else return min(query(lson, l, mid, L, R), query(rson, mid+1, r, L, R));
        }
    }
}

signed main(){
    freopen("a.in", "r", stdin), freopen("a.out", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    qr(n), qr(q), cin>>(s+1);

    f[1] = 1; s[0] = '#', s[n+1] = '@';
    for(int i=2; i<=n; i++)
        f[i] = f[i-1] + P(s[i-1], s[i]);
    
    Tree::build(1, 1, n);

    while(q--)
    {
        int qr(op);
        switch(op){
            case 1:{int qr(p); char c; cin>>c; int now = P(s[p-1], c) - P(s[p-1], s[p]);
                    Tree::update(1, 1, n, p, now); now = P(c, s[p+1]) - P(s[p], s[p+1]);
                    Tree::update(1, 1, n, p+1, now); s[p] = c;  break; }
            default:{int qr(l), qr(r); cout<<s[Tree::query(1, 1, n, l, r).pos]<<"\n"; break;}
        }
    }
    

    return 0;
}

為了方便判斷,我讓 s[0]='#',但交到 oj 上卻輸出了這個:

顯然是返回了 0,但是毫無緣由,程式碼裡註釋部分是輸出樹上所有點的 pos,結果沒有為 0 的。

相關文章