[DP 组合数学] BZOJ 4498 魔法的碰撞

来源:互联网 发布:淘宝收到货后怎么退货 编辑:程序博客网 时间:2024/05/02 01:31


传送门:http://blog.csdn.net/visit_world/article/details/51090964

dp其中一维解释一下,表示可以放且必须放的一个位置


#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define P 1000000007using namespace std;typedef long long ll;inline char nc(){static char buf[100000],*p1=buf,*p2=buf;if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }return *p1++;}inline void read(int &x){char c=nc(),b=1;for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}int maxn=1000000;ll fac[1000005],inv[1000005];inline void Pre(){fac[0]=1;for (int i=1;i<=maxn;i++)(fac[i]=fac[i-1]*i)%=P;inv[1]=1;for (int i=2;i<=maxn;i++)(inv[i]=(P-P/i)*inv[P%i])%=P;inv[0]=1;for (int i=1;i<=maxn;i++)(inv[i]*=inv[i-1])%=P;}inline ll C(int n,int m){return ((fac[n]*inv[m])%P*inv[n-m])%P;}ll f[2][3205][41];int d[45],m,n,sum;int main(){freopen("t.in","r",stdin);freopen("t.out","w",stdout);Pre();read(m), read(n);    for (int i = 1; i <= n; ++i)        read(d[i]),--d[i],sum+=d[i]<<1;    sort(d+1,d+n+1);int t=0;    f[t][0][1]=1;    for (int i=n;i;i--,t^=1)    {        memset(f[t^1],0,sizeof(f[t^1]));        int v=d[i];        for (int j=0;j<=sum;j++) for (int k=1;k<=n;k++) if (f[t][j][k])        {            ll x=f[t][j][k];            (f[t^1][j+v*2][k+1]+=x*k%P)%=P;            (f[t^1][j+v][k]+=x*k*2%P)%=P;            (f[t^1][j][k-1]+=x*k%P)%=P;        }    }    ll ret=0;    for (int j=min(sum,m-n);~j;j--)if (f[t][j][0])        (ret+=f[t][j][0]*C(m-j,n)%P)%=P;    printf("%lld\n",ret);}


0 0