1 条题解
-
0
自动搬运
来自洛谷,原作者为

Twig_K
Life will be easier when the sunlight in搬运于
2025-08-24 21:47:01,当前版本为作者最后更新于2024-12-17 11:03:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
update:代码贴错了,已修改,现在的代码可以过题。
update:修改了一处假掉的地方,感谢
luogu://user/538683
有两问,第一问中高度相同编号不同的山看作不同,第二问中高度相同的山看作相同。
第一问
题目对山的限制在于“高于它且排在它前面”的数量,比它矮的山放在哪里对它是没有影响的。因此,对于两座高度不同的山,我们先插入高度大的,即按高度降序排序。 高度相同时,按照关键字从小到大排序。
对于这一问,高度相同的山怎么排其实是无所谓的,第二问中有影响,会说明(划掉的是错的,下面会说明)。排完序之后只需要按顺序一个个插进去。设当前插入的山是 (排序后的下标),前面有 座严格比它高的山,这座山的关键数字是 ,那么对于这座山,方案数就是 。最后所有山乘起来就可以了。
上面划掉的地方就是假了的地方。原因在于,如果我们先插入限制松的,就会导致限制它的旁边放不了限制更紧的,但是我们仍然会把这个不合法的位置统计进去,这样乘法原理就不对了。
第二问
这一问中相同高度的不作区分。将相同高度的一起考虑,设高度严格大于它们的有 个。可以理解为,在 个空位中可重复地塞若干个相同小球,其中每个小球能塞的空位是一段给定的前缀。
设这些小球的选择分别是 ,由于这些小球不作区分,我们钦定 。考虑它们加入的顺序,能塞的前缀之间是包含关系,我们先插入限制紧的。因此,高度从大到小为第一关键字,关键数字从小到大为第二关键字。
排序完设 表示现在插入了前 个,第 个插入的空挡位置(总共有 个空位) 是 的方案数。 由于 ,所以,。
最后答案为每种高度的方案数相乘。
代码
#include<bits/stdc++.h> #define Spc putchar(' ') #define End putchar('\n') #define For(i,il,ir) for(int i=(il);i<=(ir);++i) #define Fr(i,il,ir) for(int i=(il);i<(ir);++i) #define Forr(i,ir,il) for(int i=(ir);i>=(il);--i) #define ForE(u) for(int i=head[u];~i;i=e[i].nxt) #define fi first #define se second #define mk make_pair #define pb emplace_back using namespace std; typedef long long ll; typedef pair<int,int> pii; namespace _OvO_{ template<typename T> inline void rd(T& x){ bool f=0;x=0;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=1; ch=getchar(); } while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(f) x=-x; } template<typename T,typename... Args> void rd(T& first,Args&... args){ rd(first),rd(args...); } int write_num[50]; inline void write(ll x){ int len=0; if(x<0) putchar('-'),x=-x; do write_num[len++]=x%10ll; while(x/=10ll); while(len--) putchar(write_num[len]+'0'); } }using namespace _OvO_; const int maxn=1005; const ll mod=2011; int n,p; pii a[maxn]; ll f[maxn][maxn],sum[maxn],ans; void solve1(){ p=0,ans=1ll; For(i,1,n){ while(a[p+1].fi>a[i].fi) p++; ans=ans*(min(a[i].se,p)+i-p)%mod; }write(ans); } void solve2() { p=0,ans=1ll; f[0][1]=1; For(i,1,n){ while(a[p+1].fi>a[i].fi) p++; For(j,1,n+1) sum[j]=(sum[j-1]+f[i-1][j])%mod; if(p==i-1){ ans=ans*sum[n+1]%mod; For(j,1,n+1) f[i-1][j]=(j==1),sum[j]=1ll; } For(j,1,min(p,a[i].se)+1) f[i][j]=sum[j]; For(j,min(p,a[i].se)+2,n+1) f[i][j]=0; } For(j,1,n+1) sum[j]=(sum[j-1]+f[n][j])%mod; write(ans*sum[n+1]%mod); } signed main() { rd(n); For(i,1,n) rd(a[i].fi,a[i].se),a[i].se--; sort(a+1,a+1+n,[&](pii xx,pii yy){ return xx.fi==yy.fi?xx.se<yy.se:xx.fi>yy.fi; }); solve1();Spc;solve2();End; return 0; }
- 1
信息
- ID
- 2328
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者