yp训练赛3/21
F题-待补
G题-待补
J题-待补
题意:
即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)
有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
思路:
卡上余额先减5块,价格排序,去掉最大值,然后01背包,这里有一个坑点,余额事先小于5块,直接输出余额,不用再去算了
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e4+10; int t,n,a[maxn],m; int dp[maxn]; int main() { while(~scanf("%d",&n)){ if(n==0){break;} for(it i=0;i<n;i++){ scanf("%d",&a[i]); } scanf("%d",&m); sort(a,a+n); mem(dp,0); dp[0]=1; int mm=m-5; if(mm<0){printf("%d\n",m);continue;} for(it j=0;j<n-1;j++){ for(it i=mm;i>=1;i--){ if(i-a[j]>=0 && dp[i-a[j]]){ dp[i]=dp[i-a[j]]; } } } int sum=0; for(it i=mm;i>=0;i--){ if(dp[i]){sum=i;break;} }//cout<<sum<<endl; printf("%d\n",m-sum-a[n-1]); } return 0; }
好像是hdu题目,做过的
题意:
就是给你n个勾子位置,m个砝码,问有多少平衡的情况
思路:
因为左边是负数,所以把20*15*25==7500扩大一倍0~7499代表左边,7501~15000代表右边,差不多背包套一下就过了
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e4+10; int n,m,c[25],g[25]; int dp[25][15010]; int main() { while(~scanf("%d%d",&n,&m)){ for(it i=0;i<n;i++){ scanf("%d",&c[i]); } for(it i=1;i<=m;i++){ scanf("%d",&g[i]); } mem(dp,0);dp[0][7500]=1; for(it i=1;i<=m;i++){ for(it j=0;j<=15000;j++){ if(dp[i-1][j]){ for(it k=0;k<n;k++){ if(j+g[i]*c[k]>=0 && j+g[i]*c[k]<=15000){ dp[i][j+g[i]*c[k]]+=dp[i-1][j]; } } } } } printf("%d\n",dp[m][7500]); } return 0; }
题意:
有两个人,有n个城堡,城堡每个都有黄金w,城堡两两连接,距离都是1
两个人的距离不能超过m,他们有 t 天可以探索城堡得到黄金,问他们最多能得到多少黄金
题目给了两人的初始点(两个人刚开始在一起),在初始点不需要花费时间就可以得到这座城堡的黄金。
思路:
肯定是从初始点左右先扩大长度,然后再判断往左还是往右得到的黄金多。模拟即可边界不能超过……
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e5+10; int t,n,pos,m; ll a[maxn]; int main() { while(~scanf("%d%d",&n,&pos)){a[0]=0; for(it i=1;i<=n;i++){scanf("%lld",&a[i]);a[i]+=a[i-1];} scanf("%d%d",&m,&t); ll ans=0; for(it i=max(1,pos-t);i<=pos;i++){ int pos2=min(i+m,pos+t);pos2=min(pos2,n); ll sum=a[pos2]-a[i-1];//cout<<pos2<<sum<<endl; int pos3=t-max(pos-i,pos2-pos); ll sum1=sum+a[i-1]-a[max(i-pos3-1,0)]; ll sum2=sum+a[min(n,pos2+pos3)]-a[pos2]; ans=max(ans,max(sum1,sum2));//cout<<ans<<sum1<<sum2<<endl; } printf("%lld\n",ans); } return 0; }
题意:
有n件物品(n<=10),有两辆车分别可以载不大于c1或者c2大小的物品,物品大小不会超过c1或者c2的。
两辆车同时出发回来,算一趟,问最少几趟可以运完
思路:
因为n<=10,可以暴力枚举出所有一趟运输的可能性fangan[],这些可能性用状态压缩保存,这里有一个状态转移方程
dp[ j | fangan[i] ]=min(dp[j]+1,dp[j | fangan[i]] );这个方程要满足j 和 fangan[i]没有交集,就是没有重复送同一件物品
可以得到dp[(1<<n)-1]就是最少的运输方案
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=(1<<10)+10; int t,n,m,c1,c2; int dp[maxn],vis[15],a[15],fan[maxn]; bool cmp(int a,int b){return a>b;} bool check(int zhi){ int sum=0,ge=0; for(it i=0;i<n;i++){ if(zhi&(1<<i)){sum+=a[i];vis[ge++]=a[i];} } if(sum>c1+c2){return 0;} int zhh=1<<ge; for(it i=1;i<zhh;i++){ int ans=0; for(it j=0;j<ge;j++){ if(i&(1<<j)){ans+=vis[j];} } //cout<<ans<<" "<<sum-ans<<endl; if(ans<=c1 && sum-ans<=c2){return 1;} if(ans<=c2 && sum-ans<=c1){return 1;} } return 0; } int main(){ scanf("%d",&t);int c=1; while(t--){ scanf("%d%d%d",&n,&c1,&c2); for(it i=0;i<n;i++){scanf("%d",&a[i]);} int zhi=1<<n,ge=0; for(it i=1;i<zhi;i++){//cout<<i<<" :"<<endl; if(check(i)){ fan[ge++]=i; } } mem(dp,inf);dp[0]=0; for(it i=0;i<ge;i++){ for(it j=zhi-1;j>=0;j--){ if((j&fan[i])==0){ dp[j|fan[i]]=min(dp[j]+1,dp[j|fan[i]]); } } } printf("Scenario #%d:\n",c++); printf("%d\n\n",dp[zhi-1]); } return 0; }
题意:
输入n,m
有n个硬币
给n个价值为ai的硬币,求最多个数的硬币,其中价值不超过m的有多少种。如果没有输出Sorry, you can't buy anything.
思路:
dp【i】【j】i表示个数,j表示价值,如果dp【i-1】【j-ai】>0,那么dp【i】【j】+=dp【i-1】【j-ai】
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e5+10; int t,n,m,a; int dp[40][510]; int main(){ scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); memset(dp,0,sizeof(dp)); dp[0][0]=1; for(it i=1;i<=n;i++){ scanf("%d",&a); for(it j=m;j>=a;j--) for(it k=i;k>=1;k--) if(dp[k-1][j-a]>0) dp[k][j]+=dp[k-1][j-a]; } int f=0,sum=0; for(it i=n;i>=1;i--){ for(it j=0;j<=m;j++){sum+=dp[i][j];} if(sum>0){ printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",sum,i);f=1;break; } } if(!f){printf("Sorry, you can't buy anything.\n");} } return 0; }
待补
D - Cash Machine
题意:
有n大小的钱包,有m种硬币,每种硬币有个数和价值,钱包里最多能放价值多少的硬币,不能超过n
思路:
完全背包,需要记录使用个数,或者二进制优化01背包
完全背包
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e5+10; ll ksm(ll a,ll b){if(b<0)return 0;ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans;} int t,n,pos,m; int dp[maxn],a[20][2],num[maxn]; int main() { while(~scanf("%d%d",&m,&n)){ for(it i=0;i<n;i++){ scanf("%d%d",&a[i][0],&a[i][1]); } mem(dp,0); for(it i=0;i<n;i++){ mem(num,0); for(it j=a[i][1];j<=m;j++){ if(dp[j]<dp[j-a[i][1]]+a[i][1] && num[j-a[i][1]]<a[i][0]){ dp[j]=dp[j-a[i][1]]+a[i][1]; num[j]=num[j-a[i][1]]+1; } } } printf("%d\n",dp[m]); } return 0; }
二进制优化
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e5+10; ll ksm(ll a,ll b){if(b<0)return 0;ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans;} int n,pos,m,cnt; int dp[maxn],a[20][2],t[maxn]; int main() { while(~scanf("%d%d",&m,&n)){cnt=0; for(it i=0;i<n;i++){ scanf("%d%d",&a[i][0],&a[i][1]); int k=1; if(a[i][0]==0||a[i][1]==0)continue; while(a[i][0]-k>0){ t[cnt++]=k*a[i][1]; a[i][0]-=k; k*=2; } t[cnt++]=a[i][0]*a[i][1]; } mem(dp,0); for(it i=0;i<cnt;i++){ for(it j=m;j>=t[i];j--){ if(dp[j]<dp[j-t[i]]+t[i]){ dp[j]=dp[j-t[i]]+t[i]; } } } printf("%d\n",dp[m]); } return 0; }
题意:
给出n,n组测试;给出最初的本金,年数;
给出d,d组银行(物品)以及每组银行的存入钱数和利息(所占容量及价值),求出几年后的最大价值。
思路:
完全背包
//#include<bits/stdc++.h> #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define ll long long #define ull unsigned long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define pii pair<int,int> #define mak(n,m) make_pair(n,m) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() const int maxn=1e5+10; ll ksm(ll a,ll b){if(b<0)return 0;ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans;} int n; int amount,y; int d; int weight[12],value[12]; int dp[1000002]; int main() { scanf("%d",&n); while(n--){ scanf("%d%d",&amount,&y); scanf("%d",&d); for (int i = 0; i < d; i += 1){ scanf("%d%d",&weight[i],&value[i]); weight[i] /= 1000; } mem(dp,0); for (int i = 0; i < y; i ++){ int tem = amount/1000; for (int j = 0; j < d; j ++){ for (int k = weight[j]; k <= tem; k += 1){ dp[k] = max(dp[k],dp[k-weight[j]]+value[j]); } } amount += dp[tem]; } printf("%d\n",amount); } return 0; }