1. 程式人生 > >suoi62 網友跳 (暴搜+dp)

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 }