对测 【离线DP+二分】

本人水平有限,题解不到为处,请多多谅解

 本蒟蒻谢谢大家观看

题目:

Market
(market.c/cpp/pas)
Input fifile: market.in
Output fifile: market.out
Time limit: 1 seconds
Memory limit: 128 megabytes
在比特镇一共有 n 家商店,编号依次为 1 到 n。每家商店只会卖一种物品,其中第 i 家商店的物品
单价为 ci,价值为 vi,且该商店开张的时间为 ti。
Byteasar 计划进行 m 次购物,其中第 i 次购物的时间为 Ti,预算为 Mi。每次购物的时候,Byteasar
会在每家商店购买最多一件物品,当然他也可以选择什么都不买。如果购物的时间早于商店开张的时间,
那么显然他无法在这家商店进行购物。
现在 Byteasar 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助
Byteasar 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
Input
第一行包含两个正整数 n, m,表示商店的总数和计划购物的次数。
接下来 n 行,每行三个正整数 ci , vi , ti,分别表示每家商店的单价、价值以及开张时间。
接下来 m 行,每行两个正整数 Ti , Mi,分别表示每个购物计划的时间和预算。
Output
输出 m 行,每行一个整数,对于每个计划输出最大可能的价值和。
Examples
market.in market.out
 
输入
5 2
5 5 4
1 3 1
3 4 3
6 2 2
4 3 2
3 8
5 9
输出
10
12
第一个计划可以在商店 2,3,5 各购买一件物品,总花费为 1 + 3 + 4 = 8,总价值为 3 + 4 + 3 = 10。
第二个计划可以在商店 1,2,3 各购买一件物品,总花费为 5 + 1 + 3 = 9,总价值为 5 + 3 + 4 = 12。
 
 
40分算法
直接背包 把总花费当做容量,总价值当做val ,再特判一下时间即可
设 f[] 为容量小于等于Mi 的最大价值和
code:
#include<bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
int n,m,sum=0,ans=0;
int f[1000001];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
struct oo{
    int c,v,t;
}a[100010];
struct node{
    int tt,mm,id;
}b[100010];
bool cmp(oo a,oo b){
    return a.t<b.t;
}
bool comp(node a,node b){
    return a.tt<b.tt;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        a[i].c=read(),a[i].v=read(),a[i].t=read();
        sum+=a[i].c;
    }
    for(int i=1;i<=m;i++){
        b[i].tt=read(),b[i].mm=read();
        b[i].id=i;
    }
    sort(a+1,a+n+1,cmp);
    //sort(b+1,b+m+1,comp);
    //f[0][0]=0;
            f[0]=0;
    for(int j=1;j<=m;j++){
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++){
            if(a[i].t<=b[j].tt){
                for(int kk=b[j].mm;kk>=a[i].c;kk--){
                    f[kk]=max(f[kk],f[kk-a[i].c]+a[i].v);
        
        //        cout<<"f[i][kk]= "<<f[i][kk]<<" i= "<<i<<" kk= "<<kk<<endl;
                }
            }
            //ans+=f[n][b[j].mm];
        }
        printf("%d
",f[b[j].mm]);
    }
    return 0;
}
/*
5 2
5 5 4
1 3 1
3 4 3
6 2 2
4 3 2
3 8
5 9
*/

100分做法:离线DP+二分

c[i](花费)很大但v[i](获得的价值)很小,

f[j]表示获利恰好为j时,所用的最小化费(初始设为正无穷)

方程f[j]=min(f[j],f[j-v[i]]+c[i])

于是对于每一个询问M,直接从后往前扫描,找到第一个小于等于M的值,其下标就是答案

这里这么设置主要是因为考虑到60%时候的方程,当M变大时,v依然很小,于是考虑把下标和数组的值更换一下位置
 
 
code:
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define N 503
#define LL long long
using namespace std;
int n,m,ans[100003];
LL f[N*N];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
struct data{
        int c,v,t,pos,num;
}b[100003],a[N],c[N];
int cmp(data a,data b){
    return a.t<b.t||a.t==b.t&&a.c>b.c;
}
int cmp1(data a,data b){
    return a.pos<b.pos||a.pos==b.pos&&a.c>b.c;
}
int calc(int x){
    int l=1;
    int r=n;
    int ans=0;
    while (l<=r){
        int mid=(l+r)/2;
         if (a[mid].t<=x){
             ans=max(ans,mid);
             l=mid+1;
         }
         else{
             r=mid-1;
         }
    }
    return ans;
}
int main(){
    n=read(),m=read();
    int sum=0;
    for (int i=1;i<=n;i++)
        a[i].c=read(),a[i].v=read(),a[i].t=read(),sum+=a[i].v;
    sort(a+1,a+n+1,cmp);
    for (int i=1;i<=m;i++)
        b[i].t=read(),b[i].c=read(),b[i].num=i;
    for (int i=1;i<=m;i++)
        b[i].pos=calc(b[i].t);
    sort(b+1,b+m+1,cmp1);
    int t=1;
    while (!b[t].pos&&t<=m)
        t++;
    memset(f,127,sizeof(f));
    LL inf=f[0];
    f[0]=0;
    for (int i=1;i<=n;i++){
        for (int j=sum;j>=a[i].v;j--)
            f[j]=min(f[j],f[j-a[i].v]+(LL)a[i].c);
    int last=sum;
    while (b[t].pos==i&&t<=m){
        for (int j=last;j>=1;j--)
            if (f[j]<=b[t].c){
                ans[b[t].num]=j;
                last=j;
                break;
            }
            t++;
        }
    }
        for (int i=1;i<=m;i++)
            printf("%d
",ans[i]);
        return 0;
}
 
 
 
 
原文地址:https://www.cnblogs.com/nlyzl/p/11561804.html