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; }