zoukankan      html  css  js  c++  java
  • 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] eq 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 }
  • 相关阅读:
    7-4
    7-3
    第五章例5-2
    第五章例5-1
    第四章例4-12
    第四章例4-11
    第四章例4-10
    第四章例4-9
    第四章例4-8
    第四章例4-7
  • 原文地址:https://www.cnblogs.com/mzg1805/p/11398123.html
Copyright © 2011-2022 走看看