標籤:style blog io sp for on 2014 log bs
- 話說這是俺們學校暑假集訓完的一道題,剛看到以為是到水題,後來發現者複雜度也太大了,受不了了,比賽完也沒搞出來,然後欣爺說這是折半枚舉。然後就摸摸的學了一下,又把這道題寫了一下,
- 所謂折半枚舉就是先算出來一半,再算一半,然後用二分尋找看看能不能搞到這一髮狀態,可以的話就是可以了,
- 題意:給你兩個數n,k,下面再給你n個數,表示你現在有的硬幣的面值,每種硬幣面值的有兩個,看是否可以支付k
- 題解思路:首先以為只有三種狀態,直接dfs就好了,後來發現複雜度太大了,然後死了擼就是上面的,詳細情殘考代碼
- 原始碼:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int a[28];long long a1[20005],a2[20005];int s,e;int T;int t1,t2;int n,k;void dfs(int x,long long v) { if(x==e) { if(e==n) a1[t1++]=v; else if(e==n/2) a2[t2++]=v; return ; } for(int i=0; i<=2; i++) dfs(x+1,v+i*a[x]);}int main() { while(scanf("%d",&T)==1) { int cases=1; while(T--) { memset(a1,0,sizeof(a1)); memset(a2,0,sizeof(a2)); scanf("%d%d",&n,&k); for(int i=0; i<n; i++) scanf("%d",&a[i]); t1=t2=0; e=n/2; dfs(0,0); e=n; dfs(n/2,0); sort(a2,a2+t2); int j,l,mid,r; for( j=0; j<t1; j++) { long long h=k-a1[j]; l=0; r=t2-1; while(l<=r) { mid =(l+r)>>1; if(a2[mid]==h)break; if(a2[mid]>h) r=mid-1; else l=mid+1; } if(l<=r) break; } if(j<t1) printf("Case %d: Yes\n",cases++); else printf("Case %d: No\n",cases++); } }}
lightoj 1235 Coin Change (IV)(折半枚舉)