H题:这题是一个变形的背包问题,注意两点:
1.数组开dp[2][],记录前一转态和后一个状态,否则超内存。
2.求最小值,这样能节省时间。
代码:
#include<iostream>
#include<cstdio>
#define maxn 1005
#define maxf 20005
#define INF 1000000
using namespace std;
int n,k,l,F;
int f[maxn],d[maxn];
int dp[2][maxf];
int DP()
{
int ans=0;
dp[0][0]=0;
for(int i=1;i<=F;i++)
{
dp[0][i]=INF;
}
for(int i=1;i<=n;i++)
{
for(int j=F;j>=0;j--)
{
dp[1][j]=INF;
//看第i个东西
if(j-f[i]>=0&&dp[0][j-f[i]]+d[i]<=l)
{
dp[1][j]=min(dp[1][j],dp[0][j-f[i]]+d[i]);
}
//不看第i个东西
if(dp[0][j]!=INF)
dp[1][j]=min(dp[1][j],max(0,dp[0][j]-k));
dp[0][j]=dp[1][j];
}
}
for(int i=F;i>=0;i--)
{
if(dp[1][i]!=INF)
{
ans=i;
break;
}
}
return ans;
}
int main()
{
while(scanf("%d%d%d",&n,&k,&l)!=EOF)
{
if(!n&&!k&&!l) break;
F=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&f[i],&d[i]);
F+=f[i];
}
printf("%d\n",DP());
}
return 0;
}
B题:这题是一个数位dp的题,主要是数位dp写的太少,基本上模式都一样。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1005
#define maxf 20005
#define INF 1000000
#define ll long long
using namespace std;
int k;
int bit[100],ans[100];
ll vis[100][100];
void init()
{
ans[0]=-111;
ans[1]=0;
for(int i=2;i<=100;i++)
{
int x=i,cnt=0;
while(x)
{
if(x%2)
cnt++;
x/=2;
}
ans[i]=ans[cnt]+1;
}
}
//下标 前面1的个数 前一位是否取最高位 前面是否全是0 当前数是1
ll dfs(int p,int num,int a,int b,int c)
{
if(p==0)
{
if(c==1) return k==0;
else return ans[num]+1==k;
}
if(a==0&&vis[p][num]>=0)
{
return vis[p][num];
}
ll ret=0;
int size=a?bit[p]:1;
for(int i=0;i<=size;i++)
{
ret+=dfs(p-1,num+(i==1),a&&(i==size),b&&(i==0),b&&(i==1));
}
return a?ret:vis[p][num]=ret;
}
ll solve(ll x)
{
if(x<=0) return 0;
if(x==1) return k==0;
int cnt=0;
while(x)
{
bit[++cnt]=x%2;
x/=2;
}
return dfs(cnt,0,1,1,0);
}
int main()
{
ll l,r;
init();
while(scanf("%lld%lld%d",&l,&r,&k)!=EOF)
{
if(!l&&!r&&!k) break;
memset(vis,-1,sizeof(vis));
ll ret=solve(r)-solve(l-1);
printf("%lld\n",ret);
}
return 0;
}