CF E. Axis Walking DP 唉。。看了别的神牛的代码忽然发现差距好大

来源:互联网 发布:亦鸥 知乎 编辑:程序博客网 时间:2024/05/21 19:35
E. Axis Walking
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Iahub wants to meet his girlfriend Iahubina. They both live in Ox axis (the horizontal axis). Iahub lives at point 0 and Iahubina at point d.

Iahub has n positive integers a1a2, ..., an. The sum of those numbers is d. Suppose p1p2, ..., pn is a permutation of {1, 2, ..., n}. Then, let b1 = ap1b2 = ap2 and so on. The array b is called a "route". There are n! different routes, one for each permutation p.

Iahub's travel schedule is: he walks b1 steps on Ox axis, then he makes a break in point b1. Then, he walksb2 more steps on Ox axis and makes a break in point b1 + b2. Similarly, at j-th (1 ≤ j ≤ n) time he walksbj more steps on Ox axis and makes a break in point b1 + b2 + ... + bj.

Iahub is very superstitious and has k integers which give him bad luck. He calls a route "good" if he never makes a break in a point corresponding to one of those k numbers. For his own curiosity, answer how many good routes he can make, modulo 1000000007 (109 + 7).

Input

The first line contains an integer n (1 ≤ n ≤ 24). The following line contains n integers: a1, a2, ..., an (1 ≤ ai ≤ 109).

The third line contains integer k (0 ≤ k ≤ 2). The fourth line contains k positive integers, representing the numbers that give Iahub bad luck. Each of these numbers does not exceed 109.

Output

Output a single integer — the answer of Iahub's dilemma modulo 1000000007 (109 + 7).

Sample test(s)
input
32 3 525 7
output
1
input
32 2 221 3
output
6
Note

In the first case consider six possible orderings:

  • [2, 3, 5]. Iahub will stop at position 2, 5 and 10. Among them, 5 is bad luck for him.
  • [2, 5, 3]. Iahub will stop at position 2, 7 and 10. Among them, 7 is bad luck for him.
  • [3, 2, 5]. He will stop at the unlucky 5.
  • [3, 5, 2]. This is a valid ordering.
  • [5, 2, 3]. He got unlucky twice (5 and 7).
  • [5, 3, 2]. Iahub would reject, as it sends him to position 5.

In the second case, note that it is possible that two different ways have the identical set of stopping. In fact, all six possible ways have the same stops: [2, 4, 6], so there's no bad luck for Iahub.    

题目意思:

 就是自己任意排放n个数据的位置,使从第一个数累加到第1或者2或3.。。n时,不能让它与k中数的任意一个相等,这算一个正确解。 然后题目要求给出所有正确解的个数,然后mod (1e9+7)。并输出答案。。


题解:

看数据量n这么小。直接建立位映射关系。
00001 表示含有 a1  00010表示含有 a2 ,00101表示a1+a3之类
bitMask[2<<24+1]    bitMask[i]=bitMask[i-lowbit(i)]+bitMask[lowbit(i)]

DP方程,i表示选择从1--j中选择i个数字,f[i][j]表示可行解
f[0]=1,表示初始状态.
假如i=1111。分别表示有a1,a2,a3,a4这几个数。则有
容易知道f[1111]=f[1110]+f[1101]+f[1011]+f[0111]


当bitMask[1111]==kk[1]或者kk[0]时,就是不可行的解,就不用计算f[1111]了。
以后在计算f之后的值时也不会重新计算进去。

。。我原先没用DP。结果写出一个超时的程序,后来看了神牛的代码,猛然醒悟好多。。顿时感觉差距还是好大好大的。。。看完后重写了一下



/* * @author ipqhjjybj * @date  20130706 * */#include <cstdio>#include <cstring>#include <iostream>#define lowbit(x) ((x)&(-x))#define ll long longusing namespace std;unsigned int bitMask[1<<24+1],f[1<<24+1];const int MOD=1e9+7;int a[26];int main(){    int n,k,kk[]={-1,0};    int i,j;    scanf("%d",&n);    for(i=0;i<n;i++){        scanf("%d",&a[i]);        bitMask[1<<i]=a[i];    }    scanf("%d",&k);    for(i=0;i<k;i++)        scanf("%d",&kk[i]);    f[0]=1;    bitMask[0]=0;    for(i=1;i<(1<<n);i++){        bitMask[i]=bitMask[i-lowbit(i)]+bitMask[lowbit(i)];        if(bitMask[i]==kk[0]||bitMask[i]==kk[1])            continue;        unsigned long long temp=0;        for(j=i;j;j-=lowbit(j)) temp+=f[i-lowbit(j)];        f[i]=temp%MOD;    }    cout<<f[(1<<n)-1]<<endl;    return 0;}


我原先的代码。。。唉。。。在第8个点超时了。。 我用的是先算出总的然后再利用容斥原理,减去不符合的解。。然后超时了,没想到神牛的加法能这么快速。膜拜啊!!

/* * @author ipqhjjybj * @date  20130706 * */#include <cstdio>#include <cstring>#include <iostream>#include <vector>#define clr(x,k) memset((x),(k),sizeof(x))#define MAX(a,b) ((a)>(b)?(a):(b))#define MAXN 10000001#define ll long long#define MOD 1000000007#define vi vector<int>using namespace std;int a[26],b[3];int n,k;ll bitMask[2<<24];ll jie[27];int p2[27];int lowbit(int x){    return x&(-x);}ll com(int i){    int j=0;    while(i){        i-=lowbit(i);        j++;    }    return jie[j]*jie[n-j];}void linecom(ll &ans,vi &line){    for(vi::iterator it=line.begin();it!=line.end();it++){        ans = (ans-com(*it)+MOD)%MOD;    }}int main(){    //freopen("E.in","r",stdin);    int i,j;    for(i=1,jie[0]=1;i<27;i++)        jie[i]=jie[i-1]*i%MOD;    for(i=1;i<27;i++)        p2[i]=1<<(i-1);    while(scanf("%d",&n)!=EOF){        for(i=1;i<=n;i++)            scanf("%d",&a[i]);        scanf("%d",&k);        for(i=0;i<k;i++)            scanf("%d",&b[i]);        clr(bitMask,0);        if(k==0){           cout<<jie[n]<<endl;            continue;        }        int numll=1<<n;        for(i=1;i<numll;i++){            for(j=1;j<=n;j++)                if(i&p2[j]){                    bitMask[i]+=a[j];                }        }        if(k==1){            vi line;            ll ans=jie[n];            for(i=1;i<numll;i++)                if(bitMask[i]==b[0])                    line.push_back(i);            linecom(ans,line);            cout<<ans<<endl;            continue;        }        if(k==2){            vi line1,line2;            ll ans=jie[n];            for(i=1;i<numll;i++)                if(bitMask[i]==b[0])                    line1.push_back(i);            for(i=1;i<numll;i++)                if(bitMask[i]==b[1])                    line2.push_back(i);            linecom(ans,line1);            linecom(ans,line2);            for(vi::iterator i1=line1.begin();i1!=line1.end();i1++){                for(vi::iterator i2=line2.begin();i2!=line2.end();i2++){                    if(((*i1)&(*i2))==(*i1)||((*i1)&(*i2))==(*i2)){                        ans = (ans+com((*i1)|(*i2))/2)%MOD;                    }                }            }            cout<<ans<<endl;            continue;        }    }    return 0;}

决定更加努力的好好学习。。

原创粉丝点击