grecil's blog

By grecil, history, 11 months ago, In English

Recently I came across several problems on different platforms that use the seemingly obscure—but actually very intuitive—idea of “Ternary Mask DP.” It’s just like bitmask DP, but instead of each bit representing two states, each digit represents three: 0, 1, or 2. The core idea is simple: convert a number into base 3, so each digit is in {0, 1, 2}. You can generalize this to any k states by using base-k.

Here’s a generalized function that encodes any integer n into an m-digit list in base k. It returns a little‑endian array of integers, but you can easily modify it to produce a string or even pack the digits into a base‑10 integer. Reverse the output if you prefer big‑endian order. (See Endianness.)

def encode_base_k(n, m, k):
    nums = []
    while n:
        n, r = divmod(n, k)
        nums.append(r)
    return nums + [0] * (m - len(nums))

Below are three examples.

1) ABC 404 D – Goin’ to the Zoo

Solution
Code

2) LC 1931 – Painting a Grid With Three Different Colors

Solution
Code

3) CF Gym 104493 A — Gym Plates

Solution
Code

Ternary (and, more generally, base‑k) mask DP lets you pack multi‑state decisions into a single integer, iterate cleanly over all possibilities, and handle compatibility with simple digit‑by‑digit checks. It’s a powerful pattern for grids, colorings, tilings, and any situation where each element has a few discrete states.

  • Vote: I like it
  • +19
  • Vote: I do not like it

»
11 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by grecil (previous revision, new revision, compare).

»
11 months ago, hide # |
 
Vote: I like it +1 Vote: I do not like it

ABC 404 D – Goin’ to the Zoo

times[i] specifies how many times each zoo is visited


/*Vidya vinayena shobhate*/ #include <bits/stdc++.h> using namespace std; //----------------------------------------------------------------------- #define JAI_SHREE_RAM cin.sync_with_stdio(false); cin.tie(0); cout.tie(0); #define ll long long #define ld long double #define py cout<<"YES\n"; #define pn cout<<"NO\n"; #define all(x) x.begin(),x.end() const ll mod = 1e9+7; const ll mod1 = 998244353; const ll N = 1e6 + 10; //----------------------------------------------------------------------- int main(){ JAI_SHREE_RAM ll T = 1; //cin >> T; while (T--){ ll n,m;cin>>n>>m; vector<ll>c(n); for(ll &i:c)cin>>i; vector<vector<ll>>zoos(n); for(ll i=0;i<m;i++){ ll cnt;cin>>cnt; for(int j=0;j<cnt;j++){ ll zoo;cin>>zoo;zoo--; zoos[zoo].push_back(i); } } ll res = 1e18; ll lim = pow(3,n); for(ll mask=0;mask<lim;mask++){ ll cur = 0; vector<ll>times(n); ll temp = mask; for(ll i=0;i<n;i++){ times[i]+=temp%3; cur += c[i]*times[i]; temp/=3; } map<ll,ll>mp; for(ll i=0;i<n;i++){ for(auto ani:zoos[i])mp[ani]+=times[i]; } bool pos = true; for(ll i=0;i<m;i++)pos &= mp[i]>=2; if(pos)res = min(res,cur); } cout<<res<<"\n"; } return 0; }
»
11 months ago, hide # |
 
Vote: I like it +1 Vote: I do not like it

1931. Painting a Grid With Three Different Colors

  • First we compute all possible bitmasks and check if they horizontally valid.
  • Second we check for every ith mask what jth masks can be in the next line.
  • Third we compute dp iteratively on the previous dp.

int mod = 1e9+7; class Solution { public: vector<int>ternary(int mask,int m){ vector<int>row(m,0); for(int i=0;i<m;i++){ row[i] = mask%3; mask /= 3; } return row; } int colorTheGrid(int m, int n) { int mx = pow(3,m); vector<vector<int>>valid; for(int mask=0;mask<mx;mask++){ auto row = ternary(mask,m); bool pos = true; for(int i=0;i<m-1;i++){ if(row[i]==row[i+1])pos = false; } if(pos)valid.push_back(row); } int v = valid.size(); vector<vector<int>>trans(v); for(int i=0;i<v;i++){ for(int j=0;j<v;j++){ bool pos = true; for(int k=0;k<m;k++)if(valid[i][k]==valid[j][k])pos=false; if(pos)trans[i].push_back(j); } } vector<long long> dp(v,1); for(int r=1;r<n;r++){ vector<long long>ndp(v,0); for(int i=0;i<v;i++)if(dp[i]){ for(int j:trans[i]){ ndp[j] = (dp[i]+ndp[j])%mod; } } swap(dp,ndp); } int res = 0; for(int d:dp)res = (res+d)%mod; return res; } };
»
11 months ago, hide # |
Rev. 3  
Vote: I like it +1 Vote: I do not like it

While reading your tutorial, I started thinking about today's POTD problem and was able to come up with a solution.

Thanks man grecil :)

»
4 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by grecil (previous revision, new revision, compare).