https://vjudge.net/contest/166969#problem/K
FFT 本渣渣是真不会。但是目标是要学会它。不要求具体会,会用板子就行。
用的数位Dp。
给定 0 1 2 3 4 这5个数,以及他们能出现的个数,问你用这些数最多能够成多少个不含前导0的n位数。
#include <iostream>
#include <cstdio>
#include <cstring>
#define mod 1000000007
#define MAXN 15005
#define LL long long int
using namespace std;
const int END=1<<5;
int n, dp[MAXN][END+5], a[10];
LL fac[MAXN], ni[MAXN], cnt[END+5];
LL quickpow(LL m,LL n)
{
int b=1;
while(n>0)
{
if(n&1)b=(b*m)%mod;
n=n>>1;
m=(m*m)%mod;
}return b;
}
int get(LL n)
{
int ans=0;
while(n>0)
{
if(n&1)
ans++;
n>>=1;
}
return ans;
}
void init()
{
fac[0]=fac[1]=ni[0]=ni[1]=1;
for(int i=2;i<=15000;++i)
{
fac[i]=fac[i-1]*i%mod;
ni[i]=quickpow(fac[i],1000000005);
}
//cnt[i]表示i中有几个1
for(int i=1;i<END;++i)cnt[i]=get(i);
}
LL c(int n,int m){return fac[n]*ni[m]%mod*ni[n-m]%mod;}
int solve()
{
memset(dp,0,sizeof dp);
for(int s=0;s<END;++s)
if(cnt[s^(END-1)]&1)dp[0][s]=-1;
else dp[0][s]=1;
for(int i=1;i<=n;++i)
{
for(int s=0;s<END;++s)
{
dp[i][s]=dp[i][s]+dp[i-1][s]*cnt[s];
for(int k=0;k<5;++k)
if(!((s>>k)&1)&&a[k]<i)
dp[i][s|(1<<k)]=dp[i][s|(1<<k)]+dp[i-1-a[k]][s]*c(i-1,a[k]);
}
}
return dp[n][END-1];
}
int work()
{
int ans=solve();
if(a[0]>0)
{
--n, --a[0];
ans=ans-solve();
}
return ans;
}
int main()
{
init();
int t, cas=0;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<5;++i)scanf("%d",&a[i]);
printf("Case #%d: %d\n",++cas,work());
}
return 0;
}