【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp
题目描述
Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a variant of the game for themselves to play. Being played by clumsy animals weighing nearly a ton, Cow Hopscotch almost always ends in disaster, but this has surprisingly not deterred the cows from attempting to play nearly every afternoon.
The game is played on an R by C grid (2 <= R <= 750, 2 <= C <= 750), where each square is labeled with an integer in the range 1..K (1 <= K <= R*C). Cows start in the top-left square and move to the bottom-right square by a sequence of jumps, where a jump is valid if and only if
1) You are jumping to a square labeled with a different integer than your current square,
2) The square that you are jumping to is at least one row below the current square that you are on, and
3) The square that you are jumping to is at least one column to the right of the current square that you are on.
Please help the cows compute the number of different possible sequences of valid jumps that will take them from the top-left square to the bottom-right square.
输入
输出
Output the number of different ways one can jump from the top-left square to the bottom-right square, mod 1000000007.
样例输入
4 4 4
1 1 1 1
1 3 2 1
1 2 4 1
1 1 1 1
样例输出
5
题解
动态开点线段树优化dp
首先有dp方程$f[x][y]=\sum\limits_{i=1}^{x-1}\sum\limits_{j=1\& c[i][j]\neq c[x][y]}^{y-1}f[i][j]=\sum\limits_{i=1}^{x-1}\sum\limits_{j=1}^{y-1}f[i][j]-\sum\limits_{i=1}^{x-1}\sum\limits_{j=1\& c[i][j]=c[x][y]}^{y-1}f[i][j]$。
前面那个东西我们可以使用二维前缀和优化,而后面的那个东西只能使用数据结构。
考虑我们的dp方式:先循环行、再循环列。那么搜到某一行时,它之前的一定是行数比它小的,所以不用管这个条件,只要维护列即可,即维护第1~x列某种颜色的f之和。
由于颜色数太多,显然不能使用静态数据结构,所以使用动态开点线段树,对每一个颜色开一棵线段树维护区间和。
对于第i行,先对于第j列求出1~j-1列与它颜色相同的f的和,然后再循环一遍,更新二维前缀和及线段树。
时间复杂度$O(nm\log nm)$
#include <cstdio>
#include <algorithm>
#define N 800
#define M 600000
using namespace std;
const int mod = 1000000007;
int c[N][N] , f[N][N] , sum[N][N] , root[M] , ls[M * 15] , rs[M * 15] , si[M * 15] , tot;
void update(int p , int a , int l , int r , int &x)
{
if(!x) x = ++tot;
si[x] = (si[x] + a) % mod;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(p , a , l , mid , ls[x]);
else update(p , a , mid + 1 , r , rs[x]);
}
int query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return si[x];
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans += query(b , e , l , mid , ls[x]);
if(e > mid) ans += query(b , e , mid + 1 , r , rs[x]);
return ans % mod;
}
int main()
{
int n , m , i , j;
scanf("%d%d%*d" , &n , &m);
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= m ; j ++ )
scanf("%d" , &c[i][j]);
f[1][1] = sum[1][1] = 1 , update(1 , 1 , 1 , m , root[c[1][1]]);
for(i = 2 ; i <= n ; i ++ ) sum[i][1] = 1;
for(i = 2 ; i <= m ; i ++ ) sum[1][i] = 1;
for(i = 2 ; i <= n ; i ++ )
{
for(j = 2 ; j <= m ; j ++ ) f[i][j] = (sum[i - 1][j - 1] - query(1 , j - 1 , 1 , m , root[c[i][j]]) + mod) % mod;
for(j = 2 ; j <= m ; j ++ ) sum[i][j] = (((sum[i][j - 1] + sum[i - 1][j]) % mod + f[i][j]) % mod - sum[i - 1][j - 1] + mod) % mod;
for(j = 2 ; j <= m ; j ++ ) update(j , f[i][j] , 1 , m , root[c[i][j]]);
}
printf("%d\n" , f[n][m]);
return 0;
}
【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp的更多相关文章
- BZOJ3939 : [Usaco2015 Feb]Cow Hopscotch
设f[i][j]表示到(i,j)的方案数,则有 $f[i][j]=\sum f[x][y](x<i,y<j,a[x][y]!=a[i][j])=\sum f[x][y](x<i,y& ...
- 【BZOJ3939】[Usaco2015 Feb]Cow Hopscotch 动态规划+线段树
[BZOJ3939][Usaco2015 Feb]Cow Hopscotch Description Just like humans enjoy playing the game of Hopsco ...
- [2016湖南长沙培训Day4][前鬼后鬼的守护 chen] (动态开点线段树+中位数 or 动规 or 贪心+堆优化)
题目大意 给定一个长度为n的正整数序列,令修改一个数的代价为修改前后两个数的绝对值之差,求用最小代价将序列转换为不减序列. 其中,n满足小于500000,序列中的正整数小于10^9 题解(引自mzx神 ...
- [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...
- 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化
4636: 蒟蒻的数列 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 247 Solved: 113[Submit][Status][Discuss ...
- codeforces 893F - Physical Education Lessons 动态开点线段树合并
https://codeforces.com/contest/893/problem/F 题意: 给一个有根树, 多次查询,每次查询对于$x$i点的子树中,距离$x$小于等于$k$的所有点中权值最小的 ...
- codeforces 915E - Physical Education Lessons 动态开点线段树
题意: 最大$10^9$的区间, $3*10^5$次区间修改,每次操作后求整个区间的和 题解: 裸的动态开点线段树,计算清楚数据范围是关键... 经过尝试 $2*10^7$会$MLE$ $10^7$会 ...
- CF915E Physical Education Lessons 动态开点线段树
题目链接 CF915E Physical Education Lessons 题解 动态开点线段树 代码 /* 动态开点线段树 */ #include<cstdio> #include&l ...
- 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)
题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...
随机推荐
- 在windows 上编译部署Rap2
在windows 上编译部署Rap2 引言 安装需要的环境 安装后端站点 创建数据库 在全局安装pm2 和 typescript 配置mysql,redis 数据库链接配置 初始化 编译 初始化数据库 ...
- [VC]ocx控件怎么屏蔽backspace的后退键
<script Language=javascript> function document.onkeydown() { if(window.event.keyCode = ...
- Android(java)学习笔记116:BroadcastReceiver之 静态注册 和 动态注册
1. 广播接受者>什么是广播.收音机.电台:对外发送信号.收音机:接收电台的信号. >在android系统里面,系统有很多重要的事件: 电池电量低,插入充电器,sd卡被移除,有电话打出去, ...
- GIT分布式版本控制器的前后今生
Git的入门与安装 GIT基础操作 GIT的分支应用 GITLAB应用 gitlab与pycharm应用 GITHUB使用
- freespace
这是一个总结freespace的博客,还不错,但算法目前看来比较老:https://blog.csdn.net/u010213183/article/details/70786516
- java基础—方法重载(overload)
一.方法的重载 方法名一样,但参数不一样,这就是重载(overload). 所谓的参数不一样,主要有两点:第一是参数的个数不一样,第二是参数的类型不一样.只要这两方面有其中的一方面不一样就可以构成方法 ...
- iOS中的数据存储方式_Preference(NSUserDefaults)
NSUserDefaults适合存储轻量级的本地数据,项目中,我会把一些简单的数据密码.网址.登陆状态BOOL.整型/浮点型数据等和用户有关的数据用它存储.但是它不能存储自定义的对象! 实例化一个 N ...
- selenium+phantomjs爬取bilibili
selenium+phantomjs爬取bilibili 首先我们要下载phantomjs 你可以到 http://phantomjs.org/download.html 这里去下载 下载完之后解压到 ...
- JAVA基础篇—继承
父类Vehicle package com.car; public class Vehicle { final String brand;// String color;// double speed ...
- micrium ucprobe使用笔记
前段时间在学习ucos-iii的时候,用到了micrium ucprobe,发现在调试的时候,很方便,可以直观的看到任务的运行使用情况,全局变量的值变化等,当然详细的可以参考官方文档,也可以参考网上的 ...