CF145C Lucky Subsequence

题目链接:
洛谷
Codeforces

Problem

这题目翻译真的神了,好多歧义,看不懂,给一个本人翻译:

给你一个长度为 \(n\) 的序列 \(a\),定义幸运数为含有 \(4\)\(7\) 的数,你需要取出它的一个的子序列,满足以下条件:

  • 长度为 \(k\)
  • 不能出现相同的幸运数,即最多 \(1\) 次,其它数可出现任意次数。

问有多少种取法,对 \(10^9+7\) 取模。

Solution

计数题,首先要想好策略,这题只有两种数,所以肯定是枚举其中一种数的个数。

对于幸运数,其数量显然不会很多,所以设 \(f(i,j)\) 为前 \(i\) 种幸运数选 \(j\) 个的方案,由于每种只能选一个,有选或不选,所以:

\[f(i,j)=f(i-1,j)+f(i-1,j-1)\times s_i \]

其中 \(s_i\) 表示第 \(i\) 种幸运数的个数。然后很容易像 01 背包一样把第一维滚掉。

对于非幸运数,直接组合数就可以了。

\(t\) 为非幸运数的个数,枚举选 \(i\) 个幸运数,所以最后的答案为:

\[\sum_{i=0}^kf_i\times \binom{t}{k-i} \]

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
void read(int &x)
{
	char ch=getchar();
	int r=0,w=1;
	while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
	while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
	x=r*w;
}
const int N=1e5+7,mod=1e9+7;
int f[N],s[N],cnt,p[N];
map<int,int>mp;
void init()
{
	p[0]=1;
	for(int i=1;i<=1e5;i++)p[i]=p[i-1]*i%mod;
}
int Pow(int x,int y)
{
	int ans=1;
	while(y)
	{
		if(y&1)ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}
int C(int n,int m)
{
	if(m==0)return 1;
	if(n<m)return 0;
	return p[n]*Pow(p[m],mod-2)%mod*Pow(p[n-m],mod-2)%mod;
}
bool check(int x)
{
	while(x)
	{
		if(x%10!=4&&x%10!=7)return false;
		x/=10;
	}
	return true;
}
main()
{
	init();
	int n,k,t=0;
	read(n);read(k);
	for(int i=1,x;i<=n;i++)
	{
		read(x);
		if(check(x))
		{
			if(!mp[x])mp[x]=++cnt;
			s[mp[x]]++;
		}
		else t++;
	}
	f[0]=1;
	for(int i=1;i<=cnt;i++)
	for(int j=cnt;j>=1;j--)
		f[j]=(f[j]+f[j-1]*s[i]%mod)%mod;
	int ans=0;
	for(int i=0;i<=k;i++)
		ans=(ans+f[i]*C(t,k-i)%mod)%mod;
	cout<<ans;
	return 0;
}
posted @ 2022-08-17 18:33  Epoch_L  阅读(22)  评论(0编辑  收藏  举报