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 ",ans); 71 return 0; 72 }