/*
idea: bfs each state. count the # of ways to do it at the end (:= a). then use an array to track, for each cell "okay, this is how many times this cell appears". preprocess this using a difference array for sweet sweet O(n)
for each cell, if its == 0, then its guaranteed '.'
               if its == a, then its guaranteed '#'
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define one first
#define two second
#define cerr if(0) cout
const int mxn = 200005;
const int mxk = 105;
int cnt[mxn][mxk];
int actualCnts[mxn][mxk];
int times[mxn];
int cantplace[mxn];
int haveplace[mxn];
int n, k;
string solve_puzzle(string s, vector<int> c) {
    // calculate ways
    n = s.size();
    k = c.size();
    memset(cnt, 0, sizeof(cnt));
    memset(haveplace, 0, sizeof(haveplace));
    memset(cantplace, 0, sizeof(cantplace));
    memset(times, 0, sizeof(times));
    for(int i = 0; i < n; i++) {
        if (s[i] == 'X') haveplace[i+1] += 1;
        if (s[i] == '_') cantplace[i+1] += 1;
        if(i) {haveplace[i+1] += haveplace[i]; cantplace[i+1] += cantplace[i];}
    }
    cnt[0][0] = 1;
    // dp[i][j] = dp[i + c[j]]
    for(int i = 1; i <= n && s[i-1] != 'X'; i++) cnt[i][0] = 1;
    for(int right = 0; right <= n; right++) cerr << 0 << ' ' << right << ' ' << cnt[right][0] << '\n';
    for(int i = 1; i <= k; i++) {
        int blockLength = c[i-1];
        
        for(int right = 1; right <= n; right++) {
            if (s[i] != 'X') cnt[right][i] += cnt[right-1][i]; // just append
            int left = right - blockLength; // this is where the "block of X" will get put
            if(left < 0) continue;
            // one indexed everything LOL
            if(cantplace[right] == cantplace[left]) { // no "_" in the range
                if(left != 0) if(s[left] == 'X') continue;
                cnt[right][i] += cnt[max(0, left-1)][i-1];
            }
            cerr << i << ' ' << right << ' ' << cnt[right][i] << '\n';
        }
    }
    queue<pair<int, int>> bfs;
    bfs.push({n, k});
    cerr << '\n';
    while(!bfs.empty()) {
        pair<int, int> curr = bfs.front(); bfs.pop();
        if(curr.two <= 0 or curr.one <= 0) continue;
        int left = curr.one - c[curr.two - 1];
        int right = curr.one;
        int timesUsed = cnt[curr.one][curr.two] - cnt[curr.one-1][curr.two];
        if(!timesUsed) continue;
        bfs.push({curr.one - 1, curr.two});
        cerr << left << ' ' << right << ' ' << timesUsed << '\n';
        times[left] += timesUsed;
        if(right < n) times[right] -= timesUsed;
        if(timesUsed) bfs.push({max(0, left - 1), curr.two - 1});
    }
    for(int i = 1; i < n; i++) {
        times[i] += times[i-1];
    }
    for(int i = 0; i < n; i++) cerr << times[i] << ' ';
    
    string ans;
    for(int i = 0; i < n; i++) {
        if(times[i] == 0) ans.push_back('_');
        else if(times[i] == cnt[n][k]) ans.push_back('X');
        else ans.push_back('?');
    }
    return ans;
}
Compilation message (stderr)
paint.h:1:9: warning: #pragma once in main file
    1 | #pragma once
      |         ^~~~
paint_c.h:1:9: warning: #pragma once in main file
    1 | #pragma once
      |         ^~~~| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |