4498: 魔法的碰撞
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 99 Solved: 64
[Submit][Status][Discuss]
Description
魔法总是令战斗的局面变幻莫测。
然而魔力的碰撞则更是天马行空,甚至会出现无法控制而自取灭亡的情况。
因此,魔力碰撞总是没有办法的办法。
不过在战场上大家可不会想太多了:看到敌人,直接一阵法术秒杀之,规则神马的都是浮云了。因此,必须布阵时就避免可能的魔力碰撞。
设想有一条长度为L的战线,你可以把你的魔法师们安排在战线上的每个格子。每一个魔法师都有一个攻击范围di,排兵时必须保证任意两个魔法师的攻击范围的较大值小于等于它们之间的距离(距离即为它们坐标的差值)。为了更好地迷惑敌人,你须要求出总共有多少种布阵的方案。
Input
第一行两个整数L,n,n代表魔法师个数。
第二行n个数,描述魔法师的攻击范围di。
N≤40,di≤40,L≤1000000
Output
一行,一个整数,代表方案数mod 1000000007的值。
Sample Input
9 3
1 2 4
Sample Output
42
HINT
Source
[Submit][Status][Discuss]
HOME Back
【分析】
奇葩脑洞题,不看题解不会系列。
正常人一眼看过去->dp[i][j]表示前i个魔法师放在前j个位置的方案数。
于是正常人发现dp[i][j]没法从dp[i][j-1]转移过来…
那好,正常人脑洞出了一个奇葩做法。
我编不下去了看链接吧 YHX Orz
http://blog.csdn.net/sdfzyhx/article/details/72773890
【代码】
//bzoj 4498 魔法的碰撞
#include<bits/stdc++.h>
#define N 1000000
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int p=1000000007;
const int mxn=1000005;
int n,l;
ll ans,fac[mxn],inv[mxn];
int d[mxn],sum[mxn];
int dp[45][45][3205];
inline bool comp(int x,int y)
{
return x>y;
}
inline void init()
{
int i,j;
fac[0]=inv[0]=inv[1]=1;
fo(i,1,N) fac[i]=fac[i-1]*i%p;
fo(i,2,N) inv[i]=(ll)(p-p/i)*inv[p%i]%p;
fo(i,1,N) inv[i]=inv[i]*inv[i-1]%p;
}
inline ll C(int n,int m)
{
if(n<m) return 0;
return fac[n]*inv[m]%p*inv[n-m]%p;
}
int main()
{
init();
int i,j,k;
scanf("%d%d",&l,&n);
fo(i,1,n) scanf("%d",&d[i]);
fo(i,1,n) d[i]--;
sort(d+1,d+n+1,comp);
dp[0][1][0]=1;
fo(i,1,n)
{
sum[i]=sum[i-1]+d[i];
fo(j,0,i+1)
fo(k,0,2*sum[i])
{
dp[i][j][k]=(dp[i][j][k]+(ll)dp[i-1][j+1][k]*(j+1)%p)%p;
if(k>=d[i])
dp[i][j][k]=(dp[i][j][k]+(ll)dp[i-1][j][k-d[i]]*2%p*j%p)%p;
if(k>=2*d[i] && j>=1)
dp[i][j][k]=(dp[i][j][k]+(ll)dp[i-1][j-1][k-2*d[i]]*(j-1)%p)%p;
}
}
fo(i,0,2*sum[n])
ans=(ans+(ll)dp[n][0][i]*C(l-i,n)%p)%p;
printf("%lld\n",ans);
return 0;
}