二进制拆分。
将一个数n拆成1,2,4,……2^(k-1),n-(2^k-1),其中k是n的二进制中1的最高位的位置。
比如6可以表示成1,2,3;4可以表示成1,2,1。
这样数0..n就可以表示为a0*1+a1*2+a2*4+……+ak-1*2^(k-1)+ak*(n-(2^k-1))。其中ai可以取0或者1。
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int cash,n;
int i,j;
int w[150];
int dp[100005];
while (scanf("%d",&cash)!=EOF)
{
memset(w,0,sizeof(w));
memset(dp,0,sizeof(dp));
int counter=0;
scanf("%d",&n);
for (i=0;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
int temp=a;
for (j=0;(a>>1)!=0;j++)
{
w[counter++]=b*(1<<j);
a>>=1;
}
w[counter++]=b*(temp-(1<<j)+1);
}
for (i=0;i<counter;i++)
for (j=cash;j>=1;j--)
if (j-w[i]>=0 && dp[j-w[i]]+w[i]>dp[j])
dp[j]=dp[j-w[i]]+w[i];
printf("%d\n",dp[cash]);
}
}