列表

详情


NC217044. CCA的序列

描述

有一个长度为 n 的整数序列,序列中的元素都从 [1,k] 中选择 。
现在你要将这个序列的长度扩充到 n+m ,即你需要从 [1,k] 中选择一些数填充到原序列的后面 m 位 。
你需要求出扩充后的序列的不同子序列的数量的最大值对 10^9+7 取模后的值 。

输入描述

第一行三个整数 n,m,k 。
第二行 n 个正整数表示原序列 。

输出描述

一个正整数表示答案对 10^9+7 取模后的值 。

示例1

输入:

2 1 3
1 2

输出:

7

说明:

最优方案是把序列变成 1 2 3,这样不同的子序列有 7 中,分别为 [1],[2],[3],[1,2],[1,3],[2,3],[1,2,3] 。

原站题解

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

C++(clang++11) 解法, 执行用时: 331ms, 内存消耗: 3352K, 提交时间: 2021-03-15 13:19:55

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int k;
int f[111];

const int mod=1e9+7;

int a[111][111];
int g1[111],g2[111][111];

struct node
{
	int pos,tot;
}e[111];

void mul(int x[111],int y[111][111])
{
	memset(g1,0,sizeof(g1));
	for(int i=1;i<=k+1;++i)
		for(int j=1;j<=k+1;++j)
			g1[i]=(g1[i]+1ll*x[j]*y[j][i]%mod)%mod;
	memcpy(f,g1,sizeof(f));
}

void mul(int x[111][111],int y[111][111])
{
	memset(g2,0,sizeof(g2));
	for(int i=1;i<=k+1;++i)
		for(int j=1;j<=k+1;++j)
			for(int l=1;l<=k+1;++l)
				g2[i][j]=(g2[i][j]+1ll*x[i][l]*y[l][j]%mod)%mod;
	memcpy(a,g2,sizeof(a)); 
}

bool cmp(node p,node q)
{
	return p.pos<q.pos;
}

int main()
{
	int n,x,sum=0,t;
	long long m;
	scanf("%d%lld%d",&n,&m,&k);
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&x);
		t=e[x].tot;
		e[x].tot=sum+1;
		e[x].pos=i;
		sum=(sum-t+mod)%mod;
		sum=(sum+e[x].tot)%mod;
	}
	sort(e+1,e+k+1,cmp); 
	for(int i=1;i<=k;++i) f[i]=e[i].tot;
	f[k+1]=1;
	for(int i=1;i<k;++i) a[i+1][i]=1; 
	for(int i=1;i<=k+1;++i) a[i][k]=1;
	a[k+1][k+1]=1;
	while(m)
	{
		if(m&1) mul(f,a);
		mul(a,a);
		m>>=1;
	}
	int ans=0;
	for(int i=1;i<=k;++i) ans=(ans+f[i])%mod;
	printf("%d",ans);
}

上一题