yp训练赛3/21

A题-饭卡

B题-Balance

C题-已补(完全背包)

D题-已补(完全背包)

E题-Treasure Hunt II

F题-待补

G题-待补

H题-Relocation

I题-Buy the souvenirs

J题-待补

 

A题-饭卡 

返回列表

题意:

即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于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;
}

 

 

 

B题-Balance

返回列表

好像是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;
}

 

 

 

E题-Treasure Hunt II

返回列表

题意:

有两个人,有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;
}

 

 

 

H题-Relocation

返回列表

题意:

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

 

 

 

I题-Buy the souvenirs

返回列表

题意:

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

 

 

 

C - Investment

题意:

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

 

 

posted @ 2020-03-21 17:09  ouluy  阅读(218)  评论(0编辑  收藏  举报