3193: [JLOI2013]地形生成
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 459 Solved: 223
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
2 1 2 2 2
Sample Output
2 2
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 = 2011; const int N = 1012; int dp[N],h[N],n,ans1 = 1,ans2 = 1; 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,0,sizeof dp); dp[0] = 1; } void read(){ scanf("%d",&n); for(int i = 1;i <= n;i++){ scanf("%d %d",&data[i].h,&data[i].d); } sort(data + 1,data + n + 1); int num = 0; for(int i = 1;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 = 1;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 = 1;k <= min(data[j].d,i) - 1;k++){ (dp[k] = dp[k - 1] + dp[k]) %= mod; } } int sum = 0; for(int j = 0;j <= min(data[pos].d,i) - 1;j++)(sum += dp[j]) %= mod; (ans2 *= sum) %= mod; i = pos; } printf(" %d\n",ans2); } int main() { read(); work(); }