列表

详情


NC17316. 挑选队友

描述

Applese打开了m个QQ群,向群友们发出了组队的邀请。作为网红选手,Applese得到了n位选手的反馈,每位选手只会在一个群给Applese反馈
现在,Applese要挑选其中的k名选手组队比赛,为了维持和各个群的良好关系,每个群中都应有至少一名选手成为Applese的队友(数据保证每个群都有选手给Applese反馈)
Applese想知道,他有多少种挑选队友的方案

输入描述

输入包括两行
第一行包括三个数n, m, k,表示共有n位选手,m个群,需要有k名选手被选择
第二行包括m个数,第i个数表示第i个群有si个选手
n ≤ 100000, m ≤ k ≤ n


输出描述

输出包括一行
第一行输出方案数
由于输出可能比较大,你只需要输出在模998244353意义下的答案

示例1

输入:

5 3 4
1 2 2

输出:

4

原站题解

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

C++14(g++5.4) 解法, 执行用时: 188ms, 内存消耗: 12896K, 提交时间: 2018-07-20 19:42:23

#include<bits/stdc++.h>
using namespace std;

typedef long long s64;
#define rep(i,l,r) for(int i=l;i<=r;++i)
const int D=998244353;
s64 mi(s64 x,int y=D-2)
{
	s64 ans=1;
	while(y)
	{
		if(y&1)ans=ans*x%D;
		x=x*x%D;y>>=1;
	}
	return ans;
}
namespace NTT
{
const int N=1<<17;
s64 a[N],b[N],w[N];
int rev[N];
void ntt(s64 a[],int n,int flag)
{
	rep(i,1,n-1)rev[i]=rev[i/2]/2+i%2*n/2;
	rep(i,1,n-1)
	if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int i=1;i<n;i*=2)
	{
		int nn=i*2;
		s64 wn=mi(3,D-1+(D-1)/nn*flag);
		w[0]=1;
		rep(k,1,i-1)w[k]=w[k-1]*wn%D;
		for(int j=0;j<n;j+=nn)
		{
			s64 *a1=a+j,*a2=a1+i;
			rep(k,0,i-1)
			{
				s64 x=a1[k],y=a2[k]*w[k]%D;
				a1[k]=(x+y)%D;
				a2[k]=(x-y)%D;
			}
		}
	}
	if(flag==-1)
	{
		s64 niv_n=mi(n);
		rep(i,0,n-1)a[i]=a[i]*niv_n%D;
	}
}
void mul(int n0)
{
	int n=1;
	while(n<=n0)n*=2;
	rep(i,n0+1,n-1)a[i]=b[i]=0;
	ntt(a,n,1);ntt(b,n,1);
	rep(i,0,n-1)a[i]=a[i]*b[i]%D;
	ntt(a,n,-1);
}
};
typedef pair<s64*,int> Poly;
const int N=1e5+5;
int a[N];
s64 jie[N];
s64 C(int n,int m)
{
	return jie[n]*mi(jie[m]*jie[n-m]%D)%D;
}
Poly solve(int l,int r)
{
	if(l==r)
	{
		s64 *f=new s64 [a[l]+1];
		f[0]=0;
		rep(i,1,a[l])f[i]=C(a[l],i);
		return Poly(f,a[l]);
	}
	int mid=(l+r)/2;
	Poly fl=solve(l,mid),fr=solve(mid+1,r);
	int n=fl.second+fr.second;
	rep(i,0,n)NTT::a[i]=NTT::b[i]=0;
	rep(i,0,fl.second)NTT::a[i]=fl.first[i];
	rep(i,0,fr.second)NTT::b[i]=fr.first[i];
	NTT::mul(n);
	s64 *f=new s64 [n+1];
	rep(i,0,n)f[i]=NTT::a[i];
	return Poly(f,n);
}

int main()
{
	//freopen("1.in","r",stdin);
	int n,m,k;
	cin>>n>>m>>k;
	rep(i,1,m)scanf("%d",a+i);
	jie[0]=1;
	rep(i,1,n)jie[i]=jie[i-1]*i%D;
	Poly f=solve(1,m);
	cout<<(f.first[k]+D)%D;
}

C++11(clang++ 3.9) 解法, 执行用时: 152ms, 内存消耗: 2792K, 提交时间: 2018-07-24 14:59:46

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 100010
#define Mod 998244353
#define LL long long
int a[N];
LL s1[N],s2[N],s[N];
LL find(LL x,LL y)
{
    LL ans=1;
    x=x%Mod;
    while(y)
    {
        if(y%2)
            ans=ans*x%Mod;
        x=x*x%Mod;
        y=y/2;
    }
    return ans;
}
LL C(int x,int y)
{
    if(x<y)
        return 0;
    return s1[x]*s2[y]%Mod*s2[x-y]%Mod;
}
int main()
{
    int n,m,k,i,j,t,d;
    LL ans;
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=m;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+m+1);
    s1[0]=1;
    for(i=1;i<=n;i++)
        s1[i]=s1[i-1]*i%Mod;
    s2[n]=find(s1[n],Mod-2);
    for(i=n;i>=1;i--)
        s2[i-1]=s2[i]*i%Mod;
    d=0;
    s[0]=1;
    for(i=1;i<=m;i++)
    {
        for(j=d+a[i];j>=a[i];j--)
            s[j]=(s[j]-s[j-a[i]])%Mod;
        d=d+a[i];
    }
    ans=0;
    for(i=0;i<=d;i++)
        ans=(ans+s[i]*C(d-i,k)%Mod)%Mod;
    ans=(ans+Mod)%Mod;
    printf("%lld\n",ans);
    return 0;
}

上一题