题目大意:给定一些山,每座山有一个高度和一个关键值,现在要将这些山排成一个序列,要求每座山之前高度高于它的山的数量不能超过它的关键值,求合法的标号序列数和高度序列数
= =
首先我们考虑第一问
我们发现高度较小的山对高度较大的山是没有影响的
那么我们可以将山按照高度从大到小排序 每座山插入时都有一些备选位置
将备选位置数相乘即是答案
现在考虑第二问
嘲讽:谁能告诉我O(n^3)到底怎么做= =
我们按照之前的思路将山按照高度从大到小排序
将高度相同的山拎出来 每一座山都有一些位置可选
那么我们不妨在排序的时候将关键值大小作为第二键值进行排序
由于同样高度的山对答案的贡献等价,那么我们不妨让关键值较小的山排在关键值较大的前面
这样得到的方案相当于一个手枪型的点阵从左下角走到右上角的方案数
每次DP一下 是O(n^2)的
虽然数据范围是1000但是由于吉林省选一贯的尿性(数据范围从来不对) O(n^3)也是能过的
只不过作为一个精神强迫症来说卡数据是不对的233
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1010 #define MOD 2011 using namespace std; struct abcd{ int height,key; bool operator < (const abcd &x) const { if( height != x.height ) return height > x.height; return key < x.key; } }a[M]; int n,ans1=1,ans2=1; int main() { int i,j,k; cin>>n; for(i=1;i<=n;i++) { scanf("%d%d",&a[i].height,&a[i].key); a[i].key--; } sort(a+1,a+n+1); for(i=1;i<=n;i=j) { static int f[M]; memset(f,0,sizeof f); f[0]=1; for(j=i;j<=n&&a[i].height==a[j].height;j++) { (ans1*=min(i-1,a[j].key)+j-i+1)%=MOD; for(k=1;k<=i-1&&k<=a[j].key;k++) (f[k]+=f[k-1])%=MOD; } int temp=0; for(k=0;k<=i-1&&k<=a[j-1].key;k++) (temp+=f[k])%=MOD; (ans2*=temp)%=MOD; } cout<<ans1<<' '<<ans2<<endl; return 0; }
时间: 2024-10-16 00:33:55