题解 SP3734 【PERIODNI - Periodni】】的更多相关文章

考虑用\(DP\)和组合数学来解决. 因为原图像不规则的形状不好处理,所以先用笛卡尔树(性质为小根堆)将其划分成一个一个的矩形. 发现在笛卡尔树上的每个节点都对应一个矩形,矩形高为\(h_x-h_{fa_x}\),宽为\(size_x\). 结合笛卡尔树的性质,不难得到,红色矩形所对应的节点的两个儿子为绿色矩形和蓝色矩形. 设\(f_{x,i}\)为在节点\(x\)所对应的矩形及其以上的图形中放\(i\)个点的方案数,那么答案为\(f_{root,k}\) 与子树合并时只需枚举在子树图像中放的点…
题解: 第一道笛卡尔树dp 会发现以一个点为分界 如果左边大于它右边大于它 那么大于的那部分是相互不影响的 于是我们对序列建立笛卡尔树 满足父亲节点的v<儿子节点的v 然后这棵树的中序遍历为原序列 这样子我们就可以dp了 考虑一个矩形的方案数 $C(n,i)*C(m,i)*i!$ 其中$i!$表示行列自由匹配 然后现在的话我们只需要统计当前点包含的行数-用掉的 以及 列 另外处理逆元前缀积有一个比正着递推常数小的方法..(少了取模和除法运算) 代码: #include <bits/stdc++…
[BZOJ2616]SPOJ PERIODNI Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output 包括一个非负整数,表示有多少种放置的方案,输出答案mod 1000000007后的结果即可. Sample Input 5 2 2 3 1 2 4 Sample Output 43 HINT 对于100%的数据,有 N≤500,K≤500,h[i] ≤1000000. 题解:一看题就感觉应该是单调…
2616: SPOJ PERIODNI Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 128  Solved: 48[Submit][Status][Discuss] Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output 包括一个非负整数,表示有多少种放置的方案,输出答案mod 1000000007后的结果即可. Sample Input 5 2…
题解: dp 方程弄出来就好做了 代码: #include<bits/stdc++.h> ,M=; typedef int arr[N]; typedef long long ll; int n,k,c[N][N],h[N]; arr g; void add(int &x,int y){x+=y;if (x>=M)x-=M;} void dfs(int l,int r,int H,arr &ans) { memset(ans,,sizeof(ans)); ans[]=;…
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2616 把相同高度的连续一段合成一个位置(可能不需要?),用前缀和维护宽度. 然后每次找区间里最低的那个点(ST表)作为根,递归左右孩子,构建笛卡尔树. dp[ cr ][ j ] 表示在 cr 的子树里选择 j 个点的方案数. 自己本来写的是同时枚举 cr 这个点.ls .rs 各贡献了多少个车,结果TLE. 看看题解,发现这样比较好(至多 \( n^3 \) ),就是先 \( dp[ c…
题意 N,K≤500,h[i]≤106N,K\le 500,h[i]\le10^6N,K≤500,h[i]≤106 题解 建立出小根堆性质的笛卡尔树,于是每个节点可以代表一个矩形,其宽度为子树大小,高度为该节点记录的那一列高度-父节点那一列高度. 然后就可以随便DP了. 如果不会笛卡尔树,看看这张图,再看看代码就懂了(简单的笛卡尔树). 代码 #include <bits/stdc++.h> using namespace std; typedef long long LL; const in…
BZOJ SPOJ 直观的想法是构建笛卡尔树(每次取最小值位置划分到两边),在树上DP,这样两个儿子的子树是互不影响的. 令\(f[i][j]\)表示第\(i\)个节点,放了\(j\)个车的方案数. 设\(v\)是\(i\)的一个儿子,对于子树部分的转移,有\[f'[i][j]=\sum_{k\leq j}f[v][j-k]f[i][k]\] 求完子树贡献后,对于\(i\)节点代表的矩形,设高度是\(h\)宽度是\(w\),有\[f'[i][j]=\sum_{k\leq j}f[i][j-k]\…
考虑建一棵小根堆笛卡尔树,即每次在当前区间中找到最小值,以最小值为界分割区间,由当前最小值所在位置向两边区间最小值所在位置连边,递归建树.那么该笛卡尔树中的一棵子树对应序列的一个连续区间,且根的权值是这段区间的最小值. 在笛卡尔树上跑树形dp.设f[i][j]为在i子树对应棋盘中放j个车的方案数,且棋盘中只考虑这段区间在根的父亲高度上方的部分.转移考虑合并两棵子树再在新增加的矩形部分放车即可,捣鼓一下组合数. #include<iostream> #include<cstdio>…
长为$A$,宽为$B$的矩阵放$K$个车的方案数$=C(A,K)\times C(B,K)\times K!$. 建立笛卡尔树,那么左右儿子独立,设$f[i][j]$表示$i$子树内放$j$个车的方案数. 合并左右儿子之后,枚举在底部矩形放几个车进行转移即可. 时间复杂度$O(n^3)$. #include<cstdio> const int N=505,M=1000005,P=1000000007; int n,m,i,a[N],mx,fac[M],inv[M],g[N],f[N][N];…