A - Max Sum Plus Plus[排列组合]
这个真的很难搞,排列组合也太难了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e6+10; const int INF = 0x7fffffff; int a[maxn]; int dp[maxn]; int Max[maxn];//max(dp[i-1][k])就是上一组0~j-1的最大值 int main(){ int n,m,mmax; while(~scanf("%d%d",&m,&n)) { for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } memset(dp,0,sizeof(dp)); memset(Max,0,sizeof(Max));//分成0组的全是0 for(int i = 1; i <= m; i++) {//分成i组 mmax = -INF; for(int j = i; j <= n; j++) {//前j个数分成i组,至少需要i个数 dp[j] = max(dp[j-1]+a[j],Max[j-1]+a[j]); //Max[j-1]目前代表的是分成i-1组前j-1个数的最大值,a[j]单独一组组成i组 //dp[j-1]代表j-1个数分成组,第j个数a[j]放在前面i组的一组中,两种方式选取较大者 Max[j-1] = mmax;//当前考虑的是j但是mmax是上一次循环得到的,所以更新的是j-1 mmax = max(mmax,dp[j]);//更新mmax,这样下次循环同样更新的是j-1 } //这样也就更新得到了分i组的Max,下次分i+1组的时候就可以使用了 } printf("%d ",mmax); } return 0; }
B - Robot[概率]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e6+10; int n,m,l,r,w; double dp[maxn],db[maxn]; int main(){ int n,m,mmax; while(~scanf("%d%d%d%d",&n,&m,&l,&r)&&(n||m||l||r)) { db[0]=1; for(int i = 1; i <= m; i++) { scanf("%d",&w); for(int j=0;j<n;++j) { if(db[j]>0)//剪枝 { dp[(j+w+n)%n] += db[j]*0.5; //向前跳w步 dp[(j-w+n)%n] += db[j]*0.5; //向后跳w步 } } memcpy(db,dp,sizeof(double)*n); memset(dp,0,sizeof(double)*n); } double re=0;l--,r--; for(int i=l;i<=r;++i) re+=db[i]; printf("%.4f ",re); memset(db,0,sizeof(dp)); memset(db,0,sizeof(db)); } return 0; }
C - Happy Matt Friends[01背包+滚动数组]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX= 1<<20; int dp[2][MAX],a[44]; int main() { int T,N,M;scanf("%d",&T); for(int t=1;t<=T;++t) { scanf("%d%d",&N,&M); memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i = 1; i <= N; i++) scanf("%d",&a[i]); for(int i=1;i<=N;++i) for(int j=0;j<MAX;++j) dp[i&1][j] = dp[(i-1)&1][j]+dp[(i-1)&1][j^a[i]]; long long re=0; int n=N&1; for(int i=M;i<MAX;++i) { re+=dp[n][i]; } printf("Case #%d: %I64d ",t,re); } return 0; }
D - 最大报销额[01背包]
背包类型变成float型了,可以先放大后缩小来变成整形
#include<iostream> #include<string.h> #include<map> #include<stdio.h> #define MAX 3000010 using namespace std; int dp[MAX],bill[MAX]; double q,temp[4]; int N,ii,m; void Copy(double temp[]) { int flag=1;double sum=0; for(int i=0;i<3;++i) { if(temp[i]>600){flag=0;break;} sum+=temp[i]; } if(sum>1000)flag=0; if(flag) { bill[ii++]=(int)(sum*100); } } int main() { while(~scanf("%lf %d",&q,&N)) { if(N==0) break; int Q=(int)(q*100);//double化整形 memset(bill,0,sizeof(bill));ii=0; for(int nn=0;nn<N;++nn)//输入N个账单 { scanf("%d",&m);getchar(); memset(temp,0,sizeof(temp));int flag=1; for(int i=0;i<m;++i)//输入账单中的每个物品 { char t;double v; scanf("%c:%lf",&t,&v); getchar(); if('A'<=t&&t<='C'){ temp[t-'A']+=v;} else { flag=0; } } if(flag)Copy(temp);//保存合法的账单 } memset(dp,0,sizeof(dp)); for(int i=0;i<ii;++i) { for(int j=Q;j>=bill[i];j--) { dp[j]=max(dp[j],dp[j-bill[i]]+bill[i]); } } printf("%.2lf ",dp[Q]/100.0); } return 0; }
E - FATE[二维完全背包]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX= 1<<20; int dp[101][101]; struct a { int v,e; }a[101]; int n,m,k,s; void f() { cout<<">>"; for(int i=1;i<=m;++i) { cout<<dp[i]<<" "; }cout<<endl; } int main() { int j,i,t; while(~scanf("%d%d%d%d",&n,&m,&k,&s)) { for(int y = 1; y <= k; y++) scanf("%d%d",&a[y].v,&a[y].e); memset(dp,0,sizeof(dp)); for(i=1;i<=k;++i) for(j=a[i].e;j<=m;++j) for(t=1;t<=s;++t) if(dp[j][t]<(dp[j-a[i].e][t-1]+a[i].v)) { dp[j][t] = dp[j-a[i].e][t-1]+a[i].v; } if(dp[m][s]>=n) { for(int h=0;h<=m;++h) { if(dp[h][s]>=n) { printf("%d ",m-h);break; } } } else printf("-1 "); } return 0; }
F - Coins[多重背包+完全背包+01背包+二进制优化]
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstring> #define MAX 1000000 using namespace std; int dp[MAX];//存储最后背包最大能存多少 int value[MAX],weight[MAX],number[MAX];//分别存的是物品的价值,每一个的重量以及数量 int bag; void ZeroOnePack(int weight,int value )//01背包 { int i; for(i = bag; i>=weight; i--) { dp[i] = max(dp[i],dp[i-weight]+value); } } void CompletePack(int weight,int value)//完全背包 { int i; for(i = weight; i<=bag; i++) { dp[i] = max(dp[i],dp[i-weight]+value); } } void MultiplePack(int weight,int value,int number)//多重背包 { if(bag<=number*weight)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包 { CompletePack(weight,value); } else//否则就将多重背包转化为01背包 { int k = 1; while(k<=number) { ZeroOnePack(k*weight,k*value); number = number-k; k = 2*k;//这里采用二进制思想 } ZeroOnePack(number*weight,number*value); } } int main() { int n; while(~scanf("%d%d",&n,&bag)) { if(n==0&&bag==0) break; int i,sum=0; for(i = 0; i<n; i++) scanf("%d",&value[i]);//输入价值 for(i=0;i<n;i++) scanf("%d",&number[i]);//输入数量 此题没有物品的重量,可以理解为体积和价值相等 memset(dp,0,sizeof(dp)); for(i = 0; i<n; i++) { MultiplePack(value[i],value[i],number[i]);//调用多重背包,注意穿参的时候分别是重量,价值和数量 } int ans=0; for(i=1;i<=bag;i++) { if(i==dp[i]) ans++; } printf("%d ",ans); } return 0; }
G - Robberies[01背包]
稍微要绕一下,被抓的概率要改成不被抓的概率,每偷一个不被抓的概率都会下降,要用乘法而不是加法
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX= 1e4+3; double dp[MAX]; struct { int m; double p; }bank[MAX]; int N,T,S; double q,temp; int main() { scanf("%d",&T); while(T--) { scanf("%lf%d",&q,&N);S=0;q=1-q; for(int i=1;i<=N;++i) { scanf("%d%lf",&bank[i].m,&bank[i].p); bank[i].p=1-bank[i].p;//转化为不被抓的概率 S+=bank[i].m; } memset(dp,0,sizeof(dp));dp[0]=1; for(int i=1;i<=N;++i) for(int j=S;j>=bank[i].m;--j) dp[j]=max(dp[j],dp[j-bank[i].m]*bank[i].p); int re=0; for(int j=S;j>=0;--j) { if(!(dp[j]<q)) { printf("%d ",j); break; } } } return 0; }
H - Max Sum[01背包]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX= 1e5+5; int dp[MAX]; int k[MAX]; int N,T; int main() { scanf("%d",&T); int re=0,l,j,r; for(int tt=1;tt<=T;++tt) { scanf("%d",&N); for(int i=1;i<=N;++i) scanf("%d",&k[i]); memset(dp,0,sizeof(dp)); l=r=j=1,re=k[1];dp[1]=k[1]; for(int i=2;i<=N;i++) { if(dp[i-1]+k[i]>=k[i]) { dp[i]=dp[i-1]+k[i]; } else { dp[i]=k[i]; j=i; } if(dp[i]>re) { re=dp[i]; l=j; r=i; } } printf("Case %d: %d %d %d ",tt,re,l,r); if(tt!=T) printf(" "); } return 0; }
I - Super Jumping! Jumping! Jumping![010背包]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX = 1002; int k[MAX],dp[MAX]; int N,T; int main() { while(~scanf("%d",&T)&&T) { memset(k,0,sizeof(k)); for(int i=1;i<=T;++i) scanf("%d",&k[i]); for(int i=1;i<=T;++i) { int big=0; for(int j=1;j<i;++j) if(k[j]<k[i]) big=max(big,dp[j]); dp[i]=big+k[i]; } int ans=-1; for(int i=1;i<=T;++i) ans=max(ans,dp[i]); cout<<ans<<endl; } return 0; }
J - Calling Extraterrestrial Intelligence Again[完全不知道哪里跟dp有关]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX = 1e5+5; int k[MAX],dp[MAX]; int N,T; int prim[MAX] = {1}, s[MAX],l=0; int m,a,b,p,q; void prime() { int i, j; memset(prim, 0, sizeof(prim)); for (i = 2; i < MAX; i++) { if (prim[i])continue; for (j = i + i; j < MAX; j += i) { prim[j] = 1; } s[l++] = i; } //s里面保存的是2-MAX的素数 } bool Check_p(int x,int y) { return (prim[x]==0)&&(prim[y]==0); } bool Check_f(int x,int y) { return a*y>x*b; } struct V { int pp,qq,mm; }big; int main() { prime(); while(~scanf("%d%d%d",&m,&a,&b)&&(m||a||b)) { int End=(int)sqrt(m); big.mm=big.pp=big.qq=0; for(int i=0;s[i]<=End;++i) { p=s[i];q=m/s[i]; while(prim[q]||Check_f(p,q)) q--; // printf("%d %d %d ",p,q,s[i]); if(big.mm<p*q) { big.mm=p*q; big.pp=p; big.qq=q; } } printf("%d %d ",big.pp,big.qq); } return 0; }