最簡單的暴力dp就是f[i][j]表示到i異或和爲j的最小花費。ios
而後咱們發現兩堆大小爲i,j的石子合併,能夠更新到一堆大小爲k=i,j最高公共的1如下都是1,以上是i|j,權值爲v1+v2的石子。ide
咱們能夠打表發現這個段數其實很小,其實也能夠嚴謹的證實或者感性理解,可是我不會。。spa
因此咱們記錄當前的全部f值以及端點而後暴力轉移就能夠了。3d
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <map> 7 #define N 100500 8 #define int long long 9 using namespace std; 10 int n,m,q,cnt1,cnt2,ans; 11 struct data{ 12 int v,l; 13 data(){} 14 data(int x,int y){v=x;l=y;} 15 bool operator < (const data & a)const{ 16 if(v==a.v)return l>a.l; 17 return v<a.v; 18 } 19 data operator + (data a){ 20 data b=data(v+a.v,l|a.l); 21 for(int i=30;~i;i--)if(l&a.l&(1<<i)) 22 {b.l|=(1<<i)-1;break;} 23 return b; 24 } 25 }f[N<<1],d; 26 signed main(){ 27 //freopen("test.in","r",stdin); 28 scanf("%lld%lld",&n,&m); 29 cnt1++; 30 f[1]=data(0,0); 31 register int i,j; 32 for(i=1;i<=n;i++){ 33 scanf("%lld%lld",&d.v,&d.l); 34 for(j=1;j<=cnt1;j++)f[cnt1+j]=f[j]+d; 35 sort(f+1,f+2*cnt1+1); 36 for(cnt2=1,j=2;j<=2*cnt1;j++) 37 if(f[j].l>f[cnt2].l)f[++cnt2]=f[j]; 38 cnt1=cnt2; 39 } 40 scanf("%lld",&q); 41 int x; 42 while(q--){ 43 scanf("%lld",&x); 44 ans=-1; 45 for(int i=1;i<=cnt1;i++)if(f[i].l>=x) 46 {ans=f[i].v;break;} 47 printf("%lld\n",ans); 48 } 49 return 0; 50 }