[Bzoj3193][JLOI2013]地形生成 (排列组合 + DP)
3193: [JLOI2013]地形生成
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 459 Solved: 223
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
对于所有的数据,有1<=N<=1000,所有的数字都是不大于109的正整数。
分析:
先考虑第一个问题(先假设没有山高度相同):
我们把所有山按高度从大到小排序,设这个集合为S,设一个空集合为V。
我们把山按顺序放入集合V。
考虑第i座山放进去的时候能放的位置,因为现在前面有i - 1座山比它高,再加上本来的第i个位置,它一共有i个位置可以放。这个山的关键值如果为k,它只能在前min(k,i)个位置里挑。
所以第i个山的放的位置的组合为ci = min(k,i)种。ans = c1 * c2 …… * cn;
但是我们现在有山的高度相同,且关键值不同。两座高度相同的山能放的最靠后的位置,一定是关键值大的那个越靠后。所以我们先按高度从大到小,然后高度相同的关键值从小到大排序出S集合。
设[x,y]这段区间的山高度相同。所以 ci = min(x,k) + i - num。因为一座山在满足关键值的情况下,可以也放在高度相同的山前面。
所以最后 得出 ans1 = c1 * c2 …… * cn;
然后再看第二个问题,会产生重复情况的只有高度相同的山放一起的情况。
我们依然排序出V集合。按顺序插入山。
定义dp状态f[i][j],表示高度相同的山里面前i座,放在前j个位置的方案数。
因为我们是插入的山,比如说在一座高度为3的山后面再插入一座高度为3的山,此时是多了一种方案,是不会重复的。
状态也是很好转移设区间[x,y]山高度相同
f[i][j] = sum(f[i - 1][k] );k <= min(data[i].d,x) - 1;
因为是按顺序来刷表的可以省掉一维。
又因为f[i][j - 1] = sum(f[i][j - 1]);f[i][j] = sum(f[i - 1][k] );k <= min(data[i - 1].d,x) - 1;所以f[i][j] = f[i - 1][j] + f[i][j - 1]
最终方程dp[i] = dp[i - 1] + dp[i]
最后把每一区间[x,y]相同的山的ci = dp[0] + dp[1] +……dp[min(data[y].d,x) - 1]乘起来。
ans2 = c1 * c2 …… * cn;
就可以了。
AC代码:
# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
const int mod = ;
const int N = ;
int dp[N],h[N],n,ans1 = ,ans2 = ;
struct Mountain{
int h;
int d;
bool operator <(const Mountain & other)const{
if(h == other.h)return d < other.d;
return h > other.h;
}
}data[N];
void Init(){
memset(dp,,sizeof dp);
dp[] = ;
}
void read(){
scanf("%d",&n);
for(int i = ;i <= n;i++){
scanf("%d %d",&data[i].h,&data[i].d);
}
sort(data + ,data + n + );
int num = ;
for(int i = ;i <= n;i++){
if(data[i].h != data[num].h)num = i;
(ans1 *= min(num,data[i].d) + i - num) %= mod;
}
printf("%d",ans1);
}
void work(){
int pos;
for(int i = ;i <= n;i++){
pos = i;
while(data[pos].h == data[i].h && pos <= n)pos++;
pos--;Init();
for(int j = i;j <= pos;j++){
for(int k = ;k <= min(data[j].d,i) - ;k++){
(dp[k] = dp[k - ] + dp[k]) %= mod;
}
}
int sum = ;
for(int j = ;j <= min(data[pos].d,i) - ;j++)(sum += dp[j]) %= mod;
(ans2 *= sum) %= mod;
i = pos;
}
printf(" %d\n",ans2);
}
int main()
{
read();
work(); }
最新文章
- fragment 重叠问题
- Convert
- 【转载】javascript与C#的语法区别
- 《所用到的AJAX技术基础》
- matlab 扩大虚拟内存
- Swift中可选类型(Optional)的用法 以及? 和 ! 的区别 (转载博客,知识分享)
- SGU 135.Drawing Lines
- swift 重载 泛式 inout的使用
- 使用Post方法模拟登陆爬取网页
- C#删除区域实现透明
- css3的动画特效--元素旋转
- 3. Java面向对象之泛型-指定多个泛型
- Laravel-任务调度
- Description Resource Path Location Type Java compiler level does not match the version of(编译问题)
- python机器可读数据-csv
- 【Spark 深入学习-08】说说Spark分区原理及优化方法
- Loj10154 选课
- 第一个map reduce程序
- java的类继承(与c++对比)
- 转Google Protocol Buffer 的使用和原理