bzoj4583: 购物

挖坑,先发代码已填

我们很容易想到一个7维DP,dp[时间][店A剩余红球][店A剩余绿球][店A剩余蓝球][店B剩余红球][店B剩余绿球][店B剩余蓝球]

然后,首先我们发现,每个时刻一个店的剩余球总数是确定的,于是就可以把其中一个球的状态去掉,于是就变成5维了。

接着,我们尝试不记录其中一个店。

我们发现,如果某一段区间两个店同时开门,那么这段时间内卖掉的球一定是那个较早关门剩余的所有球。(因为较早关门的那个店一定要卖光,然后另一个店就必须跟着卖)

然后这段时间里的方案数,直接可以用组合数算出来。

于是我们就可以直接跳过有2个店开门的时间。

于是我们的DP状态就变成3维的了,空间&&时间都是500*100*100的。

O(1)转移xjb搞一搞就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
#define N 505
#define P 1000000007
 
using namespace std;
inline int read(){
    int ret=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while ('0'<=ch&&ch<='9'){
        ret=ret*10-48+ch;
        ch=getchar();
    }
    return ret;
}
int fast_pow(int x,int y){
    int ret=1;
    while (y){
        if (y&1) ret=(ll)ret*x%P;
        x=(ll)x*x%P;
        y=y>>1;
    }
    return ret;
}
 
struct node{
    int l,c0,c1,c2;
} a[N];
inline bool operator <(const node &u,const node &v){
    return u.l<v.l;
}
int n;
int fact[N],inv[N];
 
int dp[N][N],f[N][N],sum,now;
void jump(int step){
    if (!step) return;
    if (!sum){now+=step;return;}
    memset(f,0,sizeof(f));
    for (int i=0;i<=100;++i)
        for (int j=0;j<=100;++j){
            int k=sum-i-j;
            if (k<0||k>100) continue;
            if (i) (f[i-1][j]+=dp[i][j])%=P;
            if (j) (f[i][j-1]+=dp[i][j])%=P;
            if (k) (f[i][j]+=dp[i][j])%=P;
        }
    for (int i=0;i<=100;++i)
        for (int j=0;j<=100;++j)
            dp[i][j]=f[i][j];
    ++now;--sum;
    jump(step-1);
}
 
int main(){
    for (int i=fact[0]=1;i<=500;++i) fact[i]=(ll)fact[i-1]*i%P;
    for (int i=0;i<=500;++i) inv[i]=fast_pow(fact[i],P-2);
    n=read();
    for (int i=1;i<=n;++i) a[i].l=read();
    for (int i=1;i<=n;++i) a[i].c0=read();
    for (int i=1;i<=n;++i) a[i].c1=read();
    for (int i=1;i<=n;++i) a[i].c2=read();
    sort(a+1,a+n+1);
    memset(dp,0,sizeof(dp));dp[0][0]=1;
    sum=0;now=0;
    for (int l=1;l<=n;++l){
        jump(a[l].l-now);
        memset(f,0,sizeof(f));
        int k;
        if (sum<=a[l].c0+a[l].c1+a[l].c2)
            for (int i=0;i<=a[l].c0;++i)
                for (int j=0;j<=a[l].c1;++j){
                    k=sum-i-j;
                    if (k<0||k>a[l].c2) continue;
                    (f[a[l].c0-i][a[l].c1-j]+=(ll)dp[i][j]*fact[sum]%P*inv[i]%P*inv[j]%P*inv[k]%P)%=P;
                }
        else
            for (int i=a[l].c0;i<=100;++i)
                for (int j=a[l].c1;j<=100;++j){
                    k=sum-i-j;
                    if (k<a[l].c2||k>100) continue;
                    (f[i-a[l].c0][j-a[l].c1]+=(ll)dp[i][j]*fact[a[l].c0+a[l].c1+a[l].c2]%P*inv[a[l].c0]%P*inv[a[l].c1]%P*inv[a[l].c2]%P)%=P;
                }
        for (int i=0;i<=100;++i)
            for (int j=0;j<=100;++j)
                dp[i][j]=f[i][j];
        now+=min(a[l].c0+a[l].c1+a[l].c2,sum);
        sum=abs(a[l].c0+a[l].c1+a[l].c2-sum);
    }
    jump(500);
    printf("%d\n",dp[0][0]);
    return 0;
}

  

posted @   wangyurzee  阅读(379)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示