bzoj4498

来源:互联网 发布:腾讯云域名没有备案 编辑:程序博客网 时间:2024/05/02 01:28

题意:
设想有一条长度为L的战线,你可以把n个魔法师安排在战线上的每个格子。每一个魔法师都有一个攻击范围di,排兵时必须保证任意两个魔法师的攻击范围的较大值小于等于它们之间的距离(距离即为它们坐标的差值)。为了更好地迷惑敌人,你须要求出总共有多少种布阵的方案。
N≤40,di≤40,L≤1000000

#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#include<algorithm>#define N 45#define M 1100000#define mmod 1000000007#define LL long longusing namespace std;int f[2][2*N*N][N],m,n,a[N],sum,jc[M],ny[M],ans;inline void upd(int &x,int y){    x=(x+y)%mmod;}int C(int n,int m){    return (LL)jc[n]*ny[m]%mmod*ny[n-m]%mmod;}int main(){    scanf("%d%d",&m,&n);    jc[0]=jc[1]=ny[0]=ny[1]=1;    for(int i=2;i<=m;i++)         jc[i]=(LL)jc[i-1]*i%mmod,ny[i]=(LL)(-mmod/i)*ny[mmod%i]%mmod;    for(int i=2;i<=m;i++) ny[i]=(LL)ny[i]*ny[i-1]%mmod;    for(int i=1;i<=n;i++) {scanf("%d",&a[i]);a[i]--;sum+=a[i];}    sum*=2;    sort(a+1,a+n+1);    f[0][0][1]=1;    int now=1,pre=0;    for(int i=n;i>=1;i--)    {        for(int j=0;j<=sum;j++)            for(int k=0;k<=n;k++)                f[now][j][k]=0;        for(int j=0;j<=sum;j++)            for(int k=0;k<=n;k++)            {                if(f[pre][j][k]==0) continue;                int t=f[pre][j][k];                upd(f[now][j+2*a[i]][k+1],(LL)t*k%mmod);                upd(f[now][j+a[i]][k],(LL)t*2*k%mmod);                if(k) upd(f[now][j][k-1],(LL)t*k%mmod);            }        now^=1;pre^=1;    }    for(int i=0;i<=sum;i++)    {        if(m-i<n) break;        if(f[pre][i][0]==0) continue;        int t=C(m-i,n);        upd(ans,(LL)f[pre][i][0]*t%mmod);    }    ans=(ans+mmod)%mmod;    printf("%d\n",ans);    return 0;}

题解:
丢链接跑~~
看了题解觉得很对。。问题是怎么才能想到啊><

0 0
原创粉丝点击