题解:P3120 [USACO15FEB] Cow Hopscotch G / ARIS0_0 - 13
前言
我怎么在拿线段树爆草 cdq 分治题单。拜谢线段树。
思路
有一个显然的 dp 思路,设
那么有
其中
那么考虑前缀和,设
但是这不够,你需要减掉和自己相同颜色的
那么有
但是这玩意还是
然后你发现,由于你求值的过程是一行一行来的,所以
这个东西其实不重要,重点是
具体的,根据颜色见线段树,以
注意一下卡空间即可(其实没有那么卡,只需要注意别开 long long 就能过)。
code
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define piii pair<pii, int>
#define fi first
#define se second
const int N = 755, M = (N - 5) * (N - 5) + 5, mod = 1e9 + 7;
namespace ARIS0_0{
int n, m, k, a[N][N], f[N][N];
struct segment{
int rt[M] = {0}, tr[M * 20] = {0}, ls[M * 20] = {0}, rs[M * 20] = {0}, tot = 0;
void modify(int &now, int l, int r, int pos, int x){
if (!now) now = ++ tot;
tr[now] = (tr[now] + x) % mod;
if (l == r) return ;
int mid = (l + r) >> 1;
if (pos <= mid) modify(ls[now], l, mid, pos, x);
else modify(rs[now], mid + 1, r, pos, x);
}
int query(int now, int l, int r, int lt, int rt){
if (!now || lt > rt) return 0;
if (lt <= l && r <= rt) return tr[now];
int mid = (l + r) >> 1, ans = 0;
if (lt <= mid) ans = (ans + query(ls[now], l, mid, lt, rt)) % mod;
if (mid < rt) ans = (ans + query(rs[now], mid + 1, r, lt, rt)) % mod;
return ans;
}
} seg;
void init(){
}
void solve(){
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> a[i][j];
f[1][1] = 1, seg.modify(seg.rt[0], 1, n, 1, 1), seg.modify(seg.rt[a[1][1]], 1, n, 1, 1);
for (int i = 2; i <= n; i ++ ){
for (int j = 2; j <= m; j ++ )
f[i][j] = ((seg.query(seg.rt[0], 1, n, 1, j - 1) - seg.query(seg.rt[a[i][j]], 1, n, 1, j - 1)) % mod + mod) % mod;
for (int j = 1; j <= m; j ++ ) seg.modify(seg.rt[0], 1, n, j, f[i][j]), seg.modify(seg.rt[a[i][j]], 1, n, j, f[i][j]);
}
cout << f[n][m] << "\n";
}
void single(){ init(), solve(); }
void multi(){ init(); int T; cin >> T; while (T -- ) solve(); }
void idmulti(){ init(); int id, T; cin >> id >> T; while (T -- ) solve(); }
};
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
ARIS0_0::single();
}
// 你听啊冬至的白雪
// 你听它掩饰着哽咽
// 在没有你的世界
// 再没有你的冬眠
// ARIS0_0 - 13