suoi62 网友跳 (暴搜+dp)

传送门

sbw太神啦orz

首先N<=20可以直接暴搜

然后玄学剪枝可以过18个点

那么N<=40的时候,就把它拆成两半分别暴搜,再用dp拼起来

对于前半段,设f[i][j]是开始高度为i,获得金币为j的方案数;对于后半段,设g[i][j]是结束高度为i,获得金币为j的方案数(离散化一下高度)

然而V<=4e7,并不能直接记

但其实每一段最多只有$2^{20}$种金币数,状压一下每一位选不选,再预处理出来这样的金币数是多少

然后统计答案,$ans=\sum{g[i][j]*f[k][l]},i>k,v[j]+v[l]>=M$

给f做一个前缀和,给每个状态按v排序,可以$O(n*2^{n/2})$统计答案

然后会MLE,注意到对于每种状态其实每个开始高度/结束高度 都只有选或者不选,做个前缀和最多也只有20

把int改成unsigned char 就行了(逃

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=45,maxs=(1<<20)+2;
 7 inline ll rd(){
 8     ll x=0;char c=getchar();int neg=1;
 9     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
10     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
11     return x*neg;
12 }
13 int H[maxn],N,M,v1[maxs],v2[maxs],rk1[maxs],rk2[maxs];
14 unsigned char f[42][maxs],g[42][maxs];
15 void dfs1(int x,int tar,int h,int y){
16     if(x>tar) return;
17     dfs1(x+1,tar,h,y);
18     if(H[x]>h) f[H[x]][y|(1<<(x-1))]++,dfs1(x+1,tar,H[x],y|(1<<(x-1)));
19 }
20 void dfs2(int x,int tar,int h,int y){
21     if(x<tar) return;
22     dfs2(x-1,tar,h,y);
23     if(H[x]<h) g[H[x]][y|(1<<(x-tar))]++,dfs2(x-1,tar,H[x],y|(1<<(x-tar)));
24 }
25 
26 inline bool cmp1(int a,int b){return v1[a]<v1[b];}
27 inline bool cmp2(int a,int b){return v2[a]<v2[b];}
28 int main(){
29     // freopen("62.in","r",stdin);
30     // freopen("62.out","w",stdout);
31     int i,j,k;
32     N=rd(),M=rd();
33     for(i=1;i<=N;i++){
34         rk1[i]=H[i]=rd(),rk2[i]=rd();
35     }
36     sort(rk1+1,rk1+N+1);
37     int t=unique(rk1+1,rk1+N+1)-rk1-1;
38     for(i=1;i<=N;i++)
39         H[i]=lower_bound(rk1+1,rk1+t+1,H[i])-rk1;
40     int m=N>>1;
41     int n1=(1<<m)-1,n2=(1<<(N-m))-1;
42     dfs1(1,m,0,0);
43     dfs2(N,m+1,100,0);
44     
45     f[0][0]=1;g[t+1][0]=1;
46     for(i=1;i<=t;i++){
47         for(j=0;j<=n1;j++)
48             f[i][j]+=f[i-1][j];
49     }
50     for(i=1;i<=n1;i++){
51         for(j=1;j<=m;j++)
52             if((i>>(j-1))&1) v1[i]+=rk2[j];
53     }for(i=1;i<=n2;i++){
54         for(j=1;j<=N-m;j++)
55             if((i>>(j-1))&1) v2[i]+=rk2[j+m];
56     }
57     for(i=1;i<=n1;i++) rk1[i]=i;
58     for(i=1;i<=n2;i++) rk2[i]=i;
59     sort(rk1+1,rk1+n1+1,cmp1);
60     sort(rk2+1,rk2+n2+1,cmp2);
61     ll ans=0;
62     for(i=1;i<=t+1;i++){
63         ll s=0;
64         for(j=0,k=n1;j<=n2;j++){
65             for(;k>=0&&v1[rk1[k]]+v2[rk2[j]]>=M;k--)
66                 s+=f[i-1][rk1[k]];
67             ans+=s*g[i][rk2[j]];
68         }
69     }
70     printf("%lld\n",ans);
71     return 0;
72 }

 

posted @ 2018-11-01 09:08  Ressed  阅读(125)  评论(0编辑  收藏  举报