atc abc465F 思路分享(高维前缀和及查询)

https://atcoder.jp/contests/abc465/tasks/abc465_f

题意

\(n\) 件物品,每个物品有:

  • 唯一的 \(6\) 位数字编号 \(S_i\).

  • 大小 \(V_i\).

\(q\) 个询问,每次询问给定两个 \(6\) 位编号 \(X,Y\),求满足:

\[X_j \le S_{i,j} \le Y_j \]

\(V_i\) 之和.

\(1\le n,q \le 3\times 10^5\).

思路

每一位都有上下界限制的区间查询,这是高维前缀和问题.

构建前缀和部分只需要对每一维单独做前缀和即可,查询部分需要考虑容斥.

回忆二维前缀和的区间查询:

\[pre[x_2][y_2]-pre[x_1-1][y_2]-pre[x_2][y_1-1]+pre[x_1-1][y_1-1] \]

六维是类似的,对 \(2^6\) 个角作容斥,取 \(p_1-1\) 的维数为奇则减,否则加.

时间复杂度 \(\mathcal{O}(N\cdot 10^N+Nq\cdot 2^N)\)\(N\) 是维数.

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int fac[7];

void init(){
    fac[0] = 1;
    for (int i=1;i<=6;i++){
        fac[i] = fac[i-1]*10;
    }
}

int id(string& s){
    int res = 0;
    for (int i=0;i<6;i++){
        res += fac[i]*(s[i]-'0');
    }   
    return res;
}

void solve(){
    int n;
    cin >> n;

    vector<ll> pre(fac[6]);
    for (int i=1;i<=n;i++){
        string s;
        int v;
        cin >> s >> v;
        pre[id(s)] += v;
    }

    for (int i=0;i<6;i++){
        for (int u=0;u<fac[6];u++){
            if (u/fac[i]%10){
                pre[u] += pre[u-fac[i]];
            }
        }
    }

    int q;
    cin >> q;
    while (q--){
        string s,t;
        cin >> s >> t;
        bool ok = true;

        for (int i=0;i<6;i++){
            if (s[i]>t[i]){
                ok = false;
                break;
            }
        }
        if (!ok){
            cout << 0 << '\n';
            continue;
        }

        ll res = 0;
        for (int u=0;u<1<<6;u++){
            string cur;
            bool f = true;
            for (int i=0;i<6;i++){
                if (u>>i&1){
                    cur += t[i];
                }
                else{
                    if (s[i]=='0'){
                        f = false;
                        break;
                    }
                    cur += s[i]-1;
                }
            }   

            if (f){
                res += ((6-__builtin_popcount(u))&1?-1:1)*pre[id(cur)];
            }        
        }     
        cout << res << '\n';   
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    init();

    int t = 1;
    // cin >> t;
    while (t--) solve();

    return 0;
} 
posted @ 2026-07-30 18:09  kzssCCC  阅读(5)  评论(0)    收藏  举报