【BZOJ3939】Cow Hopscotch(动态开点线段树)

题意:

就像人类喜欢跳格子游戏一样,FJ的奶牛们发明了一种新的跳格子游戏。虽然这种接近一吨的笨拙的动物玩跳格子游戏几乎总是不愉快地结束,但是这并没有阻止奶牛们在每天下午参加跳格子游戏

游戏在一个R*C的网格上进行,每个格子有一个取值在1-k之间的整数标号,奶牛开始在左上角的格子,目的是通过若干次跳跃后到达右下角的格子,当且仅当格子A和格子B满足如下条件时能从格子A跳到格子B:

1.B格子在A格子的严格右方(B的列号严格大于A的列号)

2.B格子在A格子的严格下方(B的行号严格大于A的行号)

3.B格子的标号和A格子的标号不同

请你帮助奶牛计算出从左上角的格子到右下角的格子一共有多少种不同的方案

n,m<=750,k<=n*m

思路:这题是金组的数据范围

在铜组因为数据小 裸的dp可做 金组需要优化

\[ dp[i,j]= \sum_{x=1}^{i-1}  \sum_{y=1}^{j-1}  dp[x,y]         (a[i,j]<>a[x,y]) \]

转化为左上角的所有方案-该颜色的所有方案

因为只要求保存一个版本

可以用一棵动态开点的线段树解决

修改时使用类似于主席树的方法

 1 const mo=1000000007;
 2 var t:array[0..7000000]of record
 3                            l,r,s:longint;
 4                           end;
 5
 6     sum,a,dp:array[0..800,0..800]of longint;
 7     root:array[0..1000000]of longint;
 8     f:array[0..800]of longint;
 9     n,m,i,j,s1,s2,cnt,k:longint;
10
11 procedure pushup(x:longint);
12 var l,r:longint;
13 begin
14  l:=t[x].l; r:=t[x].r;
15  t[x].s:=(t[l].s+t[r].s) mod mo;
16 end;
17
18 procedure update(var p:longint;l,r,x,v:longint);
19 var mid:longint;
20 begin
21  if p=0 then
22  begin
23   inc(cnt); p:=cnt;
24  end;
25  if l=r then
26  begin
27   t[p].s:=(t[p].s+v) mod mo; exit;
28  end;
29  mid:=(l+r)>>1;
30  if x<=mid then update(t[p].l,l,mid,x,v)
31   else update(t[p].r,mid+1,r,x,v);
32  pushup(p);
33 end;
34
35 function query(p,l,r,x,y:longint):longint;
36 var mid:longint;
37 begin
38
39  if (p=0)or(x>y) then exit(0);
40  if (x<=l)and(y>=r) then exit(t[p].s);
41  mid:=(l+r)>>1;
42  query:=0;
43  if x<=mid then query:=(query+query(t[p].l,l,mid,x,y)) mod mo;
44  if y>mid then query:=(query+query(t[p].r,mid+1,r,x,y)) mod mo;
45 end;
46
47
48 begin
49 // assign(input,‘bzoj3939.in‘); reset(input);
50 // assign(output,‘bzoj3939.out‘); rewrite(output);
51  readln(n,m,k);
52  for i:=1 to n do
53   for j:=1 to m do read(a[i,j]);
54
55  dp[1,1]:=1;
56  for i:=1 to m do sum[1,i]:=1;
57  update(root[a[1,1]],1,m,1,1);
58
59  for i:=2 to n do
60  begin
61   for j:=m downto 1 do
62   begin
63    s1:=sum[i-1,j-1];
64    s2:=query(root[a[i,j]],1,m,1,j-1);
65    dp[i,j]:=((s1-s2) mod mo+mo) mod mo;
66    update(root[a[i,j]],1,m,j,dp[i,j]);
67   end;
68   for j:=1 to m do
69   begin
70    f[j]:=(f[j-1]+dp[i,j]) mod mo;
71    sum[i,j]:=(sum[i-1,j]+f[j]) mod mo;
72   end;
73  end;
74   writeln(dp[n,m]);
75  {for i:=1 to n do
76  begin
77   for j:=1 to m do write(dp[i,j],‘ ‘);
78   writeln;
79  end; }
80
81
82  close(input);
83  close(output);
84 end.
时间: 2024-10-05 19:01:47

【BZOJ3939】Cow Hopscotch(动态开点线段树)的相关文章

【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

【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss] Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一

Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 else 区间覆盖 push_up的时候要注意好多细节,, 数组尽量往大开 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const in

【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. 输入 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初始值. 接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树).

CF1045G AI robots(动态开点线段树)

题意 火星上有$N$个机器人排成一行,第$i$个机器人的位置为$x_{i}$,视野为$r_{i}$,智商为$q_{i}$.我们认为第$i$个机器人可以看到的位置是$[x_{i}-r_{i},x_{i}+r_{i}]$.如果一对机器人相互可以看到,且它们的智商$q_{i}$的差距不大于$K$,那么它们会开始聊天. 为了防止它们吵起来,请计算有多少对机器人可能会聊天. 题解 先膜一下大佬->这里 我们先按视野降序排序,这样一个一个考虑,如果后面的能看到前面,那前面的也肯定能看到后面 这样,就是对于每

CF915E Physical Education Lessons|动态开点线段树

动态开点线段树 题目暗示了区间修改,所以我们自然想到了用线段树来维护非工作日的天数. 然而我们再看一下数据范围,天数n的范围是\(1 \le n \le 10^9\),像普通线段树一样预处理显然会爆空间. 天无绝人之路,我们看一下修改个数,$1\le q \le 3 \cdot 10^5 $, 比天数少很多,这也意味着,我们预先处理好的线段树有些节点并没有用 能否优化呢?答案是肯定的,这就是动态开点线段树,顾名思义,我们只要到用某个节点的时候,才分配一个点给它,这样使得我们使用的空间大大减少.其

动态开点线段树

用途 需要建立多棵独立的线段树 线段树维护的值域较大(1e9),但是操作次数较少(1e5) 特征 类似主席树的原理,动态分配每个树节点的位置(lson[],rson[]),每次只更新一条链,但是主席树是建立一颗新的树,动态开点线段树是在一棵树上不断添加节点(还是一棵树) 类似线段树的原理,push_down区间修改,push_up区间查询 例题 1.维护值域较大,线段树区间修改 cf915e https://codeforces.com/contest/915/problem/E 题意: q(3

HDU 6183 Color it(动态开点线段树)

题目原网址:http://acm.hdu.edu.cn/showproblem.php?pid=6183 题目中文翻译: Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 1677    Accepted Submission(s): 500 Problem Description 你喜欢画画吗? Little D不喜欢画画,特别

HDU 6681 Rikka with Cake(扫描线、动态开点线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=6681 题意 在矩形区域内有k条射线,问这些射线将矩形分成了多少区域 题解 容易发现答案为所有射线交点个数. 按y从排序扫描矩形区域,动态开点线段树维护区间内竖线的个数,由于n,m范围较大,需要离散化处理,但这样比较麻烦且此题空间足够所以建议用动态开点. 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #defi

Physical Education Lessons CodeForces - 915E (动态开点线段树)

Physical Education Lessons CodeForces - 915E This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical