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.
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
Mình có sol khác khá hay: https://docs.google.com/document/d/1dofDyFN9AM5ceEGDdIS-DDJzpNCXV-iM-nrs4d4W_1U/edit
hàng 1 là gì vậy, mảng a phải ko nhỉ, đọc editorial mình thấy hơi khó hiểu