LG3120 [USACO15FEB]Cow Hopscotch G CDQ分治维护DP顺序
题目描述
题解
容易得到转移方程 \(dp(i,j)=\sum\limits_{x=1}^{i-1}{\sum\limits_{y=1}^{j-1}{dp(x,y)|a_{i,j} \neq a_{x,y}}}\)
边界条件为 \(dp(1,1) = 1\)
然后呢,人傻了,这东西转移条件非常苛刻,都是严格小于。
人傻数据结构来凑,写个线段树套线段树吧
人又傻了,不会树套树啊。
于是可以 cdq 分治维护 dp 顺序
看这两个限制条件
\(\begin{cases} x<i\\ y<j \end{cases}\)
是一个二维偏序问题,可以强上 cdq 压掉一维。
然后就傻逼题了。
代码
#include<bits/stdc++.h>
using namespace std;
template < typename Tp >
inline void read(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= fh;
}
template < typename Tp >
inline void biread(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 2 + ch - '0', ch = getchar();
x *= fh;
}
const int mod = 1000000007;
int n, m, k;
int s[750 * 750 + 7];
int dp[757][757], a[757][757];
void cdq(int l, int r) {
if(l == r) return ;
int mid = (l + r) >> 1;
cdq(l, mid);
int total = 0;
for(int i = 1; i <= m; i++) {
for(int j = mid + 1; j <= r; j++) {
dp[i][j] = ((dp[i][j] + total - s[a[i][j]]) % mod + mod) % mod;
}
for(int j = l; j <= mid; j++) {
// dp[i][j] = (dp[i][j] + total - s[a[i][j]]) % mod;
s[a[i][j]] = (s[a[i][j]] + dp[i][j]) % mod;
total = (total + dp[i][j]) % mod;
}
}
for(int i = 1; i <= m; i++) {
for(int j = l; j <= mid; j++) s[a[i][j]] = ((s[a[i][j]] - dp[i][j]) % mod + mod) % mod;
}
cdq(mid + 1, r);
}
inline void Init(void) {
read(n); read(m); read(k);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
read(a[i][j]);
}
}
}
inline void Work(void) {
dp[1][1] = 1;
cdq(1, n);
printf("%d\n", dp[n][m]);
}
signed main(void) {
Init();
Work();
return 0;
}