3.11-3.17

lzywakaka發表於2024-03-12

天梯賽選拔第二場:

L2-1:佇列模擬

3.11-3.17
void solve() {
    int n,k;
    cin >> n >> k;
    stack<int> q,box;
    for(int i=1;i<=n;i++) {
        int x;
        cin >> x;
        q.push(x);
    }
    stack<int> res;
    vector<int> ans;
    while(q.size() || box.size()) {
        if(q.size()) {
            int x = q.top();
            q.pop();
            if(res.empty()) res.push(x);
            else {
                int y = res.top();
                if(x>y && x-y<=k) res.push(x);
                else {
                    if(box.size()) {
                        int t = box.top();
                        if(t>y && t-y<=k) {
                            res.push(t);
                            box.pop();
                        }
                    }
                    box.push(x);
                }
            }
        }
        if(q.empty()) {
            q = box;
            while(box.size()) box.pop();
            if(res.size()==1) { 
                int t = res.top();
                res.pop();
                ans.push_back(t);
            }
            else {
                while(res.size()) cout << res.top() << ' ' , res.pop();
                cout << endl;
            }
        }
    }
    for(auto & t : ans) cout << t << ' ';
}
View Code

L2-3:n有1e5大小。所以對於每一個數字,預處理每一個點長度和各個位數之和。然後對於每一個 x ,令總和為 w ,列舉前i位之和,去找滿足條件的abs(w-x)的個數。

3.11-3.17
PII get(int x) {
    PII res;
    while(x) {
        res.first++;
        res.second+=x%10;
        x/=10;
    }
    return res;
}

vector<int> get_(int x) {
    vector<int> v;
    while(x) v.push_back(x%10) ,x/=10;
    reverse(v.begin() , v.end());
    return v;
}

void solve() {
    int n;
    cin >> n;
    map<int , int> mp;
    map<int , int> len,sum,mp1,mp2,mp3,mp4;
    for(int i=1;i<=n;i++) {
        int w;
        cin >> w;
        mp[w]++;
        PII x = get(w);
        len[w]=x.first , sum[w]=x.second;
        if(x.first&1 && x.second&1) mp1[x.second]++;
        else if(x.first&1 && x.second%2==0) mp2[x.second]++;
        else if(x.first%2==0 && x.second&1) mp3[x.second]++;
        else mp4[x.second]++;
    }
    int ans=0;
    for(auto & [s,b] : mp) {
        int x = 0 , y = sum[s] , res=0;
        vector<int> v;
        v = get_(s);
        for(int j=0;j<v.size();j++) {
            x += v[j] , y -= v[j];
//            cout << x << ' ' << y << endl;
            int z = abs(x-y);
//            cout << z << endl;
            if(len[s]&1) {
                if(sum[s]&1) res+=mp1[z];
                else res+=mp2[z];
            }
            else {
                if(sum[s]&1) res+=mp3[z];
                else res+=mp4[z];
            }
        }
//        cout << "res: " << res << endl;
        ans+=res*b;
//        cout << ans << endl << endl;
    }
    cout << ans << endl;
}
View Code

L2-4:優先佇列小頂堆處理每一個節點,直到不能取為止。

3.11-3.17
void solve() {
    int n,m,x,y,t;
    cin >> n >> m >> x >> y >> t;
    vector<vector<int>> v(n+10,vector<int>(m+10));
    vector<vector<int>> f(n+10,vector<int>(m+10));
    vector<vector<bool>> vis(n+10,vector<bool>(m+10));
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            cin >> v[i][j] , f[i][j]=v[i][j];
        }
    }
    while(t--) {
        int a,b;
        cin >> a >> b;
        f[a][b]=-1;
    }
    f[x][y]=-1;
    priority_queue<PII , vector<PII> , greater<PII>> q;
    q.push({f[x][y],{x,y}});
    int power=0;
    while(q.size()) {
        int w = q.top().first , xt = q.top().second.first , yt = q.top().second.second;
        q.pop();
        if(vis[xt][yt]) continue;
        vis[xt][yt]=1;
        if(power >= w) {
            power += v[xt][yt];
            for(int i=1;i<=4;i++) {
                int xx = xt + dx[i];
                int yy = yt + dy[i];
                if(xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[xx][yy]) {
                    q.push({f[xx][yy],{xx,yy}});
                }
            }
        }
    }
    cout << power << endl;
}
View Code

L3-1:dp:令 f[n][k] 表示前n個數選k組得到的最大和。對於每組是是那個節點到哪個節點,只要

f[n][k]-f[n-m][k-1] == vis[n]-vis[n-m] 即表示這一段被選擇。

3.11-3.17
void solve() {
    int n,m,k;
    cin >> n >> m >> k;
    vector<int> v(n+10),vis(n+10);
    vector<vector<int>> f(n+10,vector<int>(k+10));
    for(int i=1;i<=n;i++) cin >> v[i] , vis[i]=vis[i-1]+v[i];
    for(int i=m;i<=n;i++) {
        for(int j=1;j<=k;j++) {
            f[i][j]=max(f[i-1][j],f[i-m][j-1]+vis[i]-vis[i-m]);
        }
    }
//    for(int i=1;i<=n;i++) {
//        for(int j=1;j<=k;j++) cout << f[i][j] << " \n"[j==k];
//    }
    vector<pair<int , int>> ans;
    int i = n , j = k;
    while(k) {
        if(f[i][k]-f[i-m][k-1]==vis[i]-vis[i-m]) {
            ans.push_back({i-m+1,i});
            i=i-m;
            k--;
        }
        else i--;
    }
    cout << f[n][j] << endl;
    reverse(ans.begin() , ans.end());
    for(auto & [a,b] : ans) cout << a << ' ' << b << endl;
}
View Code

L3-2:對於一棵樹,每次有兩種操作,要麼使某個節點值加 x ;要麼求某一個節點形成的子樹的價值是多少。

dfs序雜湊一下每個節點,然後樹狀陣列維護字首和即可。

3.11-3.17
// /l、
//(゚、 。 7
// l、 ~ヽ
// じしf_, )ノ
//  不要放棄!貓貓會為你加油!
#include <bits/stdc++.h>
#define endl '\n'
#define int long long

using namespace std;

const int N = 5e5+10 , M = 1e6+10 ;

int n,m,cnt;
int tr[N],dis[N];
vector<int> v[N];
map<int , int> mp;

int lowbit(int x) {
    return x & -x;
}

void add(int x,int d) {
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=d;
}

int query(int x) {
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}

int dfs(int x) {
    mp[x]=++cnt;
    dis[mp[x]]=1;
    for(auto & t : v[x]) {
        dis[mp[x]]+=dfs(t);
    }
    return dis[mp[x]];
}

void solve() {
    cin >> n >> m;
    vector<int> w(n+10);
    for(int i=1;i<=n;i++) cin >> w[i];
    for(int i=2;i<=n;i++) {
        int x;
        cin >> x;
        v[x].push_back(i);
    }
    dfs(1);
//    for(int i=1;i<=n;i++) cout << i << ' ' << mp[i] << ' ' << dis[mp[i]] << endl;
    for(int i=1;i<=n;i++) add(mp[i],w[i]);
//    for(int i=1;i<=n;i++) cout << query(mp[i]) - query(mp[i]-1) << endl;
    while(m--) {
        int op;
        cin >> op;
        if(op&1) {
            int x,y;
            cin >> x >> y;
            add(mp[x],y);
        }
        else {
            int x;
            cin >> x;
            cout << query(mp[x]+dis[mp[x]]-1) - query(mp[x]-1) << endl;
        }
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0) , cout.tie(0);
    int T = 1;
//    cin >> T ;
    while(T--) solve();
    return 0;
}
View Code

L3-3:求 i^j 的總和。

1 <= i <= n , 1 <= j <= n , 1 <= n <= 1e18。

從二進位制角度來看,其實就是每一位 0 的數量乘以 1 的數量在乘以當前 2 的 i 次方即可。(要開__int28)

3.11-3.17
// /l、
//(゚、 。 7
// l、 ~ヽ
// じしf_, )ノ
//  不要放棄!貓貓會為你加油!
#include <bits/stdc++.h>
#define endl '\n'
#define int __int128

using namespace std;

const int N = 2e5+10 , M = 1e6+10 , mod = 998244353;

void solve() {
    long long n;
    cin >> n;
    int ans=0;
    for(int i=60;i>=0;i--) {
        int d = (1ll<<i) , w=d-1;
        if(n<=w) continue;
        int s = n-w;
        int a = s/(d*2ll)*d , b = a;
        if(s % (d*2ll)) {
            int y = s % (d*2ll);
            if(y<d) a+=y;
            else a+=d , y-=d , b+=y;
        }
        b+=w;
        ans = (ans + a % mod * b % mod * d % mod * 2ll % mod) % mod;
    }
    cout << (long long)ans << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0) , cout.tie(0);
    long long T = 1;
    cin >> T ;
    while(T--) solve();
    return 0;
}
View Code

SMU 2024 spring 天梯賽1:

7-11:龍龍送外賣

有一棵樹,樹根是外賣店,節點上有些地方有人點外賣,問:每當有人點外賣之後,龍龍把外賣送給所有人至少需要走多少步,每兩個節點之間的距離是1。

解:畫一下圖可以發現,龍龍所走的最短距離就是所有被覆蓋的點的距離*2-離外賣店最遠的那個節點。dfs處理一下正序每個節點離外賣店的距離。倒序往回標記有哪些節點被走過。記錄一下最遠節點的距離輸出即可。

3.11-3.17
void dfs(int x,int w) {
    dis[x]=w;
    for(auto & t : ve[x]) {
        dfs(t,w+1);
    }
}

void DFS(int x) {
    vis[x]=1 , cnt++;
    for(auto & t : v[x]) {
        if(!vis[t]) DFS(t);
    }
}

void solve() {
    int root;
    cin >> n >> m;
    for(int i=1;i<=n;i++) {
        int x;
        cin >> x;
        if(x==-1) root=i;
        else {
            v[i].push_back(x);
            ve[x].push_back(i);
        }
    }
    vis[root]=1;
    dfs(root,0);
    int res=0;
    while(m--) {
        int x;
        cin >> x;
        if(!vis[x]) DFS(x);
        res=max(res,dis[x]);
        cout << cnt*2-res << endl;
    }
}
View Code

7-12:智慧護理中心統計

也是和黃金樹影一樣的,dfs序加樹狀陣列處理即可。

3.11-3.17
int n,m,cnt=0,idx=0;
vector<int> v[N];
unordered_map<string , int> mp;
int tr[N],dis[N],ru[N],hx[N];
unordered_map<int , string> lao;
bool vis[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x,int d) {
    for(int i=x;i<=cnt;i+=lowbit(i)) tr[i]+=d;
}

int query(int x) {
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}

int dfs(int x) {
    vis[x]=1;
    hx[x]=++idx;
    dis[hx[x]]=1;
    for(auto & t : v[x]) {
        if(!vis[t]) dis[hx[x]]+=dfs(t);
    }
    return dis[hx[x]];
}

void solve() {
    cin >> n >> m;
    vector<pair<int , string>> res;
    for(int i=1;i<=m;i++) {
        string A,B;
        cin >> A >> B;
        if(A[0]>='A') {
            if(!mp.count(A)) mp[A]=++cnt;
            if(!mp.count(B)) mp[B]=++cnt;
            int a = mp[A] , b = mp[B];
            v[b].push_back(a);
            ru[a]++;
        }
        else {
            int d=0;
            for(int j=0;j<A.size();j++) d = d*10 + A[j]-'0';
            res.push_back({d,B});
            if(!mp.count(B)) mp[B]=++cnt;
        }
    }
    for(auto & t : mp) {
        if(!ru[t.second]) dfs(mp[t.first]);
    }
    for(auto & [x,s] : res) {
        add(hx[mp[s]],1);
        lao[x]=s;
    }
    char op;
    while(cin >> op && op!='E') {
        if(op=='Q') {
            string s;
            cin >> s;
            cout << query(hx[mp[s]]+dis[hx[mp[s]]]-1) - query(hx[mp[s]]-1) << endl;
        }
        else {
            int x;
            string s;
            cin >> x >> s;
            if(lao.count(x)) {
                string w = lao[x];
                add(hx[mp[w]],-1);
                add(hx[mp[s]],1);
            }
            else {
                add(hx[mp[s]],1);
            }
            lao[x]=s;
        }
    }
}
View Code

相關文章