Editorial for Bedao Regular Contest 16 - DOMINO


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Ta giả sử ~a_i \le b_i~ với mọi ~i~. Khi đó gọi ~w_1, w_2, ..., w_m~ là các tổng có thể tạo được ở hàng 1. Vậy để tìm hiệu bé nhất, ta cần tìm ~w_i~ lớn nhất thỏa mãn ~w_i\le \frac{a_1+a_2+..+a_n+b_1+b_2+...+b_n}{2}~

Mà ~a_i,b_i\le6 \Rightarrow |w_i-w_{i+1}|\le5~. Theo đó, ta chỉ cần duyệt từ ~sum=\frac{a_1+a_2+..+a_n+b_1+b_2+...+b_n}{2}~ giảm dần và kiểm tra có thể tạo được tổng có giá trị như vậy hay không bằng cách giải hệ:

~x_1+2x_2+3x_3+4x_4+5x_5=sum~

~x_1< v_1 + 1,x_2< v_2 + 1,x_3< v_3 + 1,x_4< v_4 + 1,x_5< v_5 + 1~

Trong đó: - ~v_x~ là số vị trí ~i~ mà tại đó ~b_i-a_i=x~

Sử dụng Digit DP:

  • ~f(id, j, carry, mask)~: Có thể tạo được số mà khớp đến chữ số thứ ~id~ của ~sum~ đồng thời số thứ ~j~ trong 5 số; biến nhớ đang nhớ một lượng là ~carry~, và ~mask~ mô tả trạng thái của 5 biến (Bit thứ ~t~ mô tả ~x_t~ đã bé hơn ~v_t+1~ hay chưa)
  • Có thể chứng minh ~carry \le 225~, vì vậy tại một trạng thái mà ~carry \ge 255~ thì ta biết trạng thái đó không thỏa mãn.
  • Gọi ~d~ là số chữ số của ~sum~ và ~x~ là chữ số ở vị trí cao nhất của ~sum~, đáp án là ~f(d - 1,5, x,2^5-1)~

Code mẫu

#include <bits/stdc++.h>
#define BIT(x, i) (((x)>>(i))&1)
#define MASK(i) (1LL<<(i))
#define fi first
#define se second
#define all(x) x.begin(), x.end()
#define discrete(x) x.resize(unique(all(x)) - x.begin())
#define mp make_pair
#define pb push_back
#define TASK "test"

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<pii> vii;
typedef vector<ll> vll;
typedef vector<pll> vlll;

template<typename T1, typename T2> bool mini(T1 &a, T2 b) {if(a>b) a=b; else return 0; return 1;}
template<typename T1, typename T2> bool maxi(T1 &a, T2 b) {if(a<b) a=b; else return 0; return 1;}
template<typename T1> T1 abs(T1 a) {if(a<0) a*=-1; return a;}

mt19937_64 rd(chrono::steady_clock::now().time_since_epoch().count());
ll rand(ll l, ll h){return l + ll(rd()) * rd() %(h-l+1);}

int n;
vector<int> a;
int sum;
vector<vector<int>> v;

struct Answer {
    bool isValid;
    vector<int> ans;

    Answer() {
        isValid = false;
    }

    Answer(bool isValid, vector<int> ans) : isValid(isValid), ans(ans) {}
};

struct DP {
    int n;
    vector<int> sum;
    vector<vector<int>> v;
    map<tuple<int, int, int, int>, bool> dp;

    void init_sum(int x) {
        for(;x;x/=10) sum.pb(x%10);
        n = sum.size();
    }

    void init_v(const vector<vector<int>> &x) {
        vector<int> V;
        v.resize(x.size());
        for(auto k: x) V.push_back(k.size());
        for(int i=0; i<6; i++) {
            for(int j=0; j<n; j++, V[i]/=10) v[i].push_back(V[i]%10);
        }
    }

    DP(int sum, const vector<vector<int>> &v) {
        init_sum(sum);
        init_v(v); 

        // cout<<"sum = "<<sum<<"\n";
        // for(int i=0; i<n; i++) cout<<this->sum[i]<<" \n"[i+1==n];
        // for(int j=0; j<6; j++)
        // {
        //     for(int i=0; i<n; i++) cout<<this->v[j][i]<<" \n"[i+1==n];
        // }
    }

    bool Magic(int i, int j, int carry, int isLeading) {
        if(i == n) return carry == 0 && isLeading == (MASK(6) - 1);
        if(dp.count({i, j, carry, isLeading})) return dp[{i, j, carry, isLeading}];
        if(j == 6) {
            if(carry % 10 == sum[i])
                return dp[{i, j, carry, isLeading}] = Magic(i+1, 0, carry/10, isLeading);
            return dp[{i, j, carry, isLeading}] = false;
        }
        if(BIT(isLeading, j)) {
            return dp[{i, j, carry, isLeading}] = Magic(i, j+1, carry + v[j][i] * j, isLeading);
        }

        bool res = false;
        for(int x = 0; x <= 9 && !res; x++) {
            res |= Magic(i, j+1, carry + x * j, isLeading);
            if(x < v[j][i]) res |= Magic(i, j+1, carry + x * j, isLeading | (MASK(j)));
        }

        return dp[{i, j, carry, isLeading}] = res;
    }

    vector<int> trace(int i, int j, int carry, int isLeading) {
        // cout<<"trace "<<i<<" "<<j<<" "<<carry<<" "<<isLeading<<"\n";
        if(i == n) return vector<int>(6, 0);
        if(j == 6) {
            // cout<<"gone to j == 6\n";
            return trace(i+1, 0, carry/10, isLeading);
        }
        if(BIT(isLeading, j)) {
            // cout<<"gone to BIT(isLeading, j)\n";
            vector<int> res = trace(i, j+1, carry + v[j][i] * j, isLeading);
            res[j] *= 10;
            res[j] += v[j][i];
            // cout<<"res = (from trace("<<i<<", "<<j+1<<", "<<carry + v[j][i] * j<<", "<<isLeading<<"))";
            // for(int &x: res) cout<<x<<" "; cout<<"\n";
            return res;
        }

        for(int x = 0; x <= 9; x++) {
            if(Magic(i, j+1, carry + x * j, isLeading)) {
                // cout<<"gone to Magic(i, j+1, carry + x * j, isLeading) with x = "<<x<<"\n";
                vector<int> res = trace(i, j+1, carry + x * j, isLeading);
                res[j] *= 10;
                res[j] += x;
                // cout<<"res = (from trace("<<i<<", "<<j+1<<", "<<carry + v[j][i] * j<<", "<<isLeading<<"))";
                // for(int &x: res) cout<<x<<" "; cout<<"\n";
                return res;
            }
            if(x < v[j][i] && Magic(i, j+1, carry + x * j, isLeading | (MASK(j)))) {
                // cout<<"gone to Magic(i, j+1, carry + x * j, isLeading | (MASK(j))) with x = "<<x<<"\n";
                vector<int> res = trace(i, j+1, carry + x * j, isLeading | (MASK(j)));
                res[j] *= 10;
                res[j] += x;        
                // cout<<"res = (from trace("<<i<<", "<<j+1<<", "<<carry + v[j][i] * j<<", "<<isLeading<<"))";
                // for(int &x: res) cout<<x<<" "; cout<<"\n";
                return res;
            }
        }
    }

    Answer run() {
        Answer res;
        for(int mask=0; mask < MASK(6); mask++) if(Magic(0, 0, 0, mask)) {
            res = Answer(true, trace(0, 0, 0, mask));
            break;
        }
        return res;
    }
};

void varify(const Answer &res, int s) {
    vector<int> tmp;
    for(int i=0; i<6; i++) {
        for(int j=0; j<res.ans[i]; j++) tmp.push_back(v[i][j]);
    }
    int S = 0;
    for(int x: tmp) S += a[x];
    if(S == s) cout<<"OK\n";
    else cout<<"WRONG\n";
}
vi A, B;

void print_sol(vi tmp) {
    // cout<<"tmp = \n"; for(int x: tmp) cout<<x<<" "; cout<<'\n';
    vi flag(n, 0);
    for(int i=0; i<n; i++) if(A[i] > B[i]) flag[i] = 1;
    // cout<<"flag = \n"; for(int x: flag) cout<<x<<" "; cout<<'\n';
    for(int i=0; i<n; i++) if(flag[i]) swap(A[i], B[i]);
    for(int i=0; i<n; i++) {
        if(tmp[B[i] - A[i]] == 0) continue;
        tmp[B[i] - A[i]]--;
        flag[i] ^= 1;
        swap(A[i], B[i]);
    }

    int top = 0, bot = 0;
    for(int i=0; i<n; i++) {
        top += A[i];
        bot += B[i];
    }
    // cout<<"top = "<<top<<", bot = "<<bot<<'\n';
    vector<int> abc;
    for(int i=0; i<n; i++) if(flag[i]) abc.push_back(i + 1);
    cout << abc.size() << ' ';
    for (int v : abc) cout << v << ' ';
}

void proc(const int &TTT)
{
    v.resize(6);
    cin>>n;
    a.resize(n);
    for(int &x: a) {
        cin>>x;
        A.push_back(x);
    }
    for(int &x: a) {
        int c; cin>>c;
        x = abs(x - c);
        B.push_back(c);
    }
    for(int x: a) sum += x;
    // cout<<"a = \n";
    // for(int x: a) cout<<x<<' '; cout<<'\n';
    // cout<<"sum = "<<sum<<'\n';
    for(int i=0; i<n; i++) v[a[i]].pb(i);
    for(int s = sum / 2; s; s--) {
        Answer res = DP(s, v).run();
        if(res.isValid == false) continue;

        // cout<<"Sum = "<<sum<<'\n';
        // cout<<"s = "<<s<<'\n';
        // for(int i=0; i<6; i++) {
        //     cout<<"res.ans["<<i<<"] = "<<res.ans[i]<<'\n';
        // }

        // varify(res, s);
        cout<<sum - 2 * s<<'\n';
        vi tmp;
        for(int i=0; i<6; i++) {
            for(int j=0; j<res.ans[i]; j++) tmp.pb(v[i][j] + 1);
        }
        print_sol(res.ans);
        return;
    }
}

int main()
{
    // freopen(TASK".inp", "r", stdin);
    // freopen(TASK".out", "w", stdout);
    ios_base::sync_with_stdio(0); cin.tie(0);
    int numTest = 1; 
    // cin>>numTest;
    for(int i=1; i<=numTest; i++) proc(i);
    return 0;
}

Comments

Please read the guidelines before commenting.