题解:AT_agc026_d [AGC026D] Histogram Coloring

· · 题解

牛逼题。

我们首先观察一下这个所谓的四方格里有 2 个 1 的结构是什么样子。

考虑第 i 列和第 i+1 列,它们的状态从下至上分别是 a_1,a_2,\cdots,a_{h_i} 和 b_1,b_2,\cdots,b_{h_{i+1}}。

令 c_i = a_i+b_i,那么合法条件实际上就是 \forall j \in [1,\min(h_i,h_{i+1})),c_j+c_{j+1} = 2。

那么实际上,我们可以发现:要么有

\forall j \in [1,\min(h_i,h_{i+1})), c_j \equiv 1 \pmod 2

要么 c_j 在 0,2,0,2 \cdots 之间交替。

也就是说,两个相邻列合法,当且仅当在共同高度以下,出现两种情况之一:

  1. 两列逐格取反;
  2. 两列逐格相同,且在共同高度内 0,1 交替出现。

于是,我们可以考虑把“上下交替”看做一种会被强制传播的性质。

我们设 dp_{i,j} 为已经考虑完了前 i 列,并且第 i 列被左侧强制成 0,1 交替的最大高度为 j 的方案数,而 j 以上的位置还未完全统计(或者说不确定)。并且在 1 \sim j 中,虽然结构已经确定,但具体以 1 开头还是以 0 开头,尚未确定。

先不用管“强制”指什么,我们待会再看。

这里,我们使用一个 trick:我们将 dp 的转移方法由“从后面接取前面的贡献”,转换为“将前面已经处理好的贡献转移到后面”。

我们考虑如何将 dp_i 的贡献放到 dp_{i+1} 中。

首先,画个图:

我们设 H = \min(h_i,h_{i+1}),mn = \min(H,j),mx = \max(H,j)。

首先,我们观察到有一些“自由格”,也就是不受限制的格子。它们是 (mx,h_i] 之间的格子。

它们在参与转移的时候,贡献永远是一个 2 的次幂,于是我们设 w = 2^{h_i-mx}。

我们刚刚已经把两相邻列的合法情况分成了两类:相同型与取反型,即逐格相同或逐格取反。

我们一个一个考虑。

然后解释一下 j=0 的特殊情形。

然后你会发现 $h_i$ 实际大得离谱,但是我们敏锐的发现离散化一下就好了。一个值域连续段中的答案显然是相同的。 :::success[AC code] ```cpp line-numbers #include<bits/stdc++.h> #define int long long using namespace std; constexpr int N = 1e2+5,mod = 1e9+7; int n,a[N],lsh[N],len = 0,dp[N][N]; inline int qpow(int base,int e){ int res = 1; while(e){ if(e&1){ res = res*base%mod; } base = base*base%mod; e>>=1; } return res; } signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin >> n; for(int i = 1;i<=n;++i){ cin >> a[i]; lsh[++len] = a[i]; } sort(lsh+1,lsh+len+1); len = unique(lsh+1,lsh+len+1)-lsh-1; for(int i = 1;i<=n;++i){ a[i] = lower_bound(lsh+1,lsh+len+1,a[i])-lsh; } dp[1][0] = 1; for(int i = 1;i<=n;++i){ int h = min(a[i],a[i+1]); for(int j = 0;j<=len;++j){ if(!dp[i][j]){ continue; } int mx = max(j,h),mn = min(j,h); int w = qpow(2,lsh[a[i]]-lsh[mx]); dp[i+1][mn] = (dp[i+1][mn]+w*dp[i][j])%mod; if(!(i == n&&j == 0)){ dp[i+1][h] = (dp[i+1][h]+w*dp[i][j])%mod; } } } cout << dp[n+1][0]; return 0; } ``` ::: 那么最后的特判是什么意思? ```cpp line-numbers if(!(i == n&&j == 0)){ dp[i+1][h] = (dp[i+1][h]+w*dp[i][j])%mod; } ``` 在处理到第 $n$ 列的时候,我们发现 $H = mn = 0$,那么两个分支都会落到 $dp_{n+1,0}$ 上。 若 $j>0$,那么第 $n$ 列从 $0$ 开始还是从 $1$ 开始未被确定,需要乘 $2$。 若 $j=0$,那么第 $n$ 列的开头元素已经被确定了,其颜色已经由自由格贡献 $w$ 统计完毕了。此时若再做统计,就会重复贡献。