列表

详情


NC21617. 楼房

描述

给你n个数1 2 3。。n,代表n个楼,第i个楼的高度为i,每个楼会有一种颜色

现在问有多少的排列满足从左往右(站在左边很远的地方看)看能看到L种颜色(即看到了L-1次颜色的变化),答案对1e9+9取模

如果两个相同颜色楼的高度分别为H1,H2 (H1 < H2), H1在左边,且H1 H2之间的楼都比H1矮,那么站在左边来看就是一种颜色

你能看到一个楼的前提是这个楼之前的楼都比它矮

输入描述

第一行输入两个整数n,L(1 ≤ n ≤ 1296) , (1 ≤ L ≤ n)

第二行输入 n个整数ci表示每个楼的颜色  (1 ≤ ci ≤ n)

输出描述

输出一个整数

示例1

输入:

4 3
1 1 2 1

输出:

6

说明:

1, 2, 3, 4 (1,2同色,看上去就是一种颜色,因此这个排列只能看到3种颜色)

1, 3, 2, 4

1, 3, 4, 2

2, 1, 3, 4

2, 3, 1, 4

2, 3, 4, 1

示例2

输入:

8 5
1 2 2 3 3 3 1 4

输出:

432

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 121ms, 内存消耗: 20116K, 提交时间: 2019-12-11 22:33:45

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll ans,n,m,p=1e9+9,jc[2010],ny[2010],a[2010],b[1301][1301],g[1301][1301],f[1301];
ll ksm(ll x,ll y){
	ll xlh=1;
	while(y){
		if(y&1)xlh=xlh*x%p;
		x=x*x%p;
		y/=2;
	}
	return xlh;
}
int main(){
	ll i,j;
	scanf("%lld%lld",&n,&m);
	jc[0]=ny[0]=1;
	for(i=1;i<=n;i++)jc[i]=jc[i-1]*i%p,ny[i]=ksm(jc[i],p-2);
	for(i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(i=1;i<=n/2;i++)swap(a[i],a[n-i+1]);
	g[a[1]][1]=1;f[1]=1;b[1][1]=1;
	ans=(ans+b[1][m]*jc[n-1])%p;
	for(i=2;i<=n;i++){
		for(j=1;j<i;j++){
			b[i][j+1]=(b[i][j+1]+f[j]*jc[i-2]%p)%p;
			b[i][j+1]=(b[i][j+1]-g[a[i]][j]*jc[i-2]%p+p+g[a[i]][j+1]*jc[i-2]%p)%p;
	   }
	   b[i][1]=g[a[i]][1]*jc[i-2]%p;
	   for(j=1;j<=i;j++)f[j]=(f[j]+b[i][j]*ny[i-1]%p)%p,g[a[i]][j]=(g[a[i]][j]+b[i][j]*ny[i-1]%p)%p;
	   ans=(ans+b[i][m]*jc[n-1]%p*ny[i-1])%p;
	   //printf("%lld\n",ans);
	}
	printf("%lld",ans);
}

上一题