P3120 [USACO15FEB]牛跳房子(线段树优化$dp$($CDQ$分治))

${\color{cyan}{>>Question}}$

很容易想到朴素方程,令$f[i][j]$表示到$i$行,$j$列的方案数

$$f[i][j] = \sum f[k][l]\;(k<i,l<j,a[k][l] \neq a[i][j])$$

但显然是$O(n^4)$的,其实这看起来就想二维偏序,但实际它有三个条件,可以$CDQ$分治(但我不会)

考虑吧方程换个形式,令$sum = \sum f[k][l]\;(k<i,l<j)$,$x = \sum f[k][l]\;(k<i,l<j,a[k][l] = a[i][j])$

$$f[i][j] = sum - x$$

(类似那道染色的思想)

可以一行一行地推(就能不用二维线段树,只用一维),令$sum[i]$表示$(1,1)$到上一行$i$列的矩形区域的前缀和(原本是二维,现在只用一维)

对于每种标记开一颗线段树,即开$k$颗线段树,这时便需要动态开点

时间复杂度 $O(n*m*\log m)$

空间复杂度 $O(k*\log m)$

代码如下

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <cstdio>
 5 #define ll long long
 6 using namespace std; 
 7 
 8 template <typename T> void in(T &x) {
 9     x = 0; T f = 1; char ch = getchar();
10     while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
11     while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();}
12     x *= f;
13 }
14 
15 template <typename T> void out(T x) {
16     if(x < 0) x = -x , putchar('-');
17     if(x > 9) out(x/10);
18     putchar(x%10 + 48);
19 }
20 //-------------------------------------------------------
21 
22 const int N = 800,mod = 1e9+7;
23 
24 int n,m,k;
25 int a[N][N];ll f[N][N],sum[N];
26 int cnt,rt[N*N];
27 struct node {
28     int lc,rc; ll sum;
29 }t[6000000];
30 
31 void A(int &u,int l,int r,int pos,int add) {
32     if(!u) u = ++cnt;
33     if(l == r) {t[u].sum = (t[u].sum+add)%mod; return;}
34     int mid = (l+r)>>1;
35     if(pos <= mid) A(t[u].lc,l,mid,pos,add);
36     else A(t[u].rc,mid+1,r,pos,add);
37     t[u].sum = (t[t[u].lc].sum + t[t[u].rc].sum)%mod;
38 }
39 
40 ll Q(int u,int l,int r,int a,int b) {
41     if(!u) return 0;
42     if(a <= l && b >= r) return t[u].sum;
43     int mid = (l+r)>>1,res = 0;
44     if(a <= mid) res = (res + Q(t[u].lc,l,mid,a,b))%mod;
45     if(b > mid) res = (res + Q(t[u].rc,mid+1,r,a,b))%mod;
46     return res;
47 }
48 
49 int main() {
50     freopen("0.in","r",stdin);
51     int i,j;
52     in(n); in(m); in(k);//
53     for(i = 1;i <= n; ++i) for(j = 1;j <= m; ++j) in(a[i][j]);//
54     f[1][1] = 1; A(rt[a[1][1]],1,m,1,1); 
55     //sum[1] = 1;
56     for(i = 1;i <= m; ++i) sum[i] = 1;//
57     for(i = 2;i <= n; ++i) {
58         for(j = 2;j <= m; ++j) {
59             f[i][j] = (sum[j-1] - Q(rt[a[i][j]],1,m,1,j-1))%mod;
60             //A(rt[a[i][j]],1,m,j,f[i][j]);//debug 当前的线段树保存的是上一行的信息,要推完这一行才能更新 
61         }
62         ll tmp = 0;
63         for(j = 2;j <= m; ++j) {
64             tmp = (tmp + f[i][j])%mod;
65             sum[j] = (sum[j] + tmp)%mod;
66             A(rt[a[i][j]],1,m,j,f[i][j]);//right
67         }
68     }
69     out((f[n][m]+mod)%mod);
70     return 0;
71 }

 

转载于:https://www.cnblogs.com/mzg1805/p/11398123.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值