# BZOJ4710: [Jsoi2011] special products (principle of tolerance and exclusion + combinatorial mathematics + DP)

Posted by Paulkirkewalker on Tue, 31 Mar 2020 19:10:03 +0200

Topic analysis: at first, I didn't have a clue at all. Later, I found out that this is just like the second kind of stirling number?

First of all, consider how to do without the condition that everyone should take at least one specialty. Because different specialty products are independent, h[i][j] can be recorded to indicate the number of programs that I personally took J specialty products before. The transfer equation is h[i][j] = ∑ j k = 0h [I − 1][k]h[i][j] = ∑ k=0jh[i − 1][k], which can be optimized with prefix. For different specialties, the number of schemes can be multiplied.

But some people in the scheme calculated in this way will not get specialty. Let's remember that f(i) means the number of programs that just i people get the specialty, and g(i) means the number of programs that at most i people get the specialty. Obviously:

g(i)=∑j=1iCjif(j)g(i)=∑j=1iCijf(j)

The reason to multiply the number of combinations is that each person has a different number. You can get:

f(i)=∑j=1i(−1)i−jCjig(j)f(i)=∑j=1i(−1)i−jCijg(j)

g(i) can be obtained by h array, and the answer is f(n). Time complexity O(nm)O(nm).

CODE:

```#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;

const int maxn=1010;
const long long M=1000000007;
typedef long long LL;

LL f[maxn][maxn];
LL sum[maxn][maxn];

LL fac[maxn];
LL nfac[maxn];

int num[maxn];
int n,m;
LL ans=0;

LL C(int N,int mm)
{
LL val=fac[N];
val=val*nfac[mm]%M;
val=val*nfac[N-mm]%M;
return val;
}

int main()
{
freopen("4710.in","r",stdin);
freopen("4710.out","w",stdout);

scanf("%d%d",&n,&m);
int Mn=0;
for (int i=1; i<=m; i++) scanf("%d",&num[i]),Mn=max(Mn,num[i]);

f=1;
for (int j=0; j<=Mn; j++) sum[j]=1;
for (int i=1; i<=n; i++)
{
for (int j=0; j<=Mn; j++) f[i][j]=sum[i-1][j];
sum[i]=f[i];
for (int j=1; j<=Mn; j++) sum[i][j]=(sum[i][j-1]+f[i][j])%M;
}

fac=1;
for (LL i=1; i<=n; i++) fac[i]=fac[i-1]*i%M;
nfac=nfac=1;
for (LL i=2; i<=n; i++)
{
LL x=M/i,y=M%i;
nfac[i]=M-x*nfac[y]%M;
}
for (int i=2; i<=n; i++) nfac[i]=nfac[i-1]*nfac[i]%M;

for (int i=1; i<=n; i++)
{
LL temp=1;
for (int j=1; j<=m; j++) temp=temp*f[i][ num[j] ]%M;
temp=temp*C(n,i)%M;
if ((n-i)&1) temp=(M-temp)%M;
ans=(ans+temp)%M;
}
printf("%lld\n",ans);

return 0;
}```

Topics: PHP