这一题让我对状态压缩的理解又深入了一层啊,之前一直在考虑,怎么处理当达到一个药效的时候有多个质量的情况,其实状态压缩就是处理这种初一看状态不是很好转移或转移的时间复杂度太大或状态不容易表示的问题的,压缩后状态减少一维,这样就会方便很多,记录路径用一个数组二位数组就OK了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#define low(a) a&-a
using namespace std;
long long dp[200010];
map<long long,int> h;
int w[410],t[410],r[200010][52],M[410],S[410];
int main()
{
//freopen("in.txt","r",stdin);
int CASE;
scanf("%d",&CASE);
for(int i=0;i<=50;i++) h[(1LL)<<i]=i;
long long up=(1LL<<52)-1;
while(CASE--){
int n,q,Max=0;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&t[i]);
for(int i=1;i<=q;i++){
scanf("%d%d",&M[i],&S[i]);
if(S[i]>Max) Max=S[i];
}
memset(dp,0,sizeof(dp));
memset(r,0,sizeof(r));
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=Max;j>=t[i];j--){
long long tm=dp[j]|(dp[j-t[i]]<<w[i]);
long long diff=tm^dp[j];
dp[j]=tm;
while(diff){
long long temp=low(diff);
diff^=temp;
temp=h[temp];
if(temp>50) break;
r[j][temp]=i;
}
}
for(int i=1;i<=q;i++){
if(!r[S[i]][M[i]]) printf("No solution!\n");
else{
while(true){
printf("%d",r[S[i]][M[i]]);
int ts=S[i],tm=M[i];
if((M[i]-w[r[ts][tm]])==0){
cout<<endl;
break;
}
else{
M[i]-=w[r[ts][tm]];
S[i]-=t[r[ts][tm]];
cout<<" ";
}
}
}
}
}
return 0;
}