可撤销背包 与 单调队列优化背包

2287: 【POJ Challenge】消失之物

首先我们有f[]表示所有物品都考虑时的方案数或者最大价值。
使用g[j]表示不选x物品时总重量为j的方案数或者价值最大值,就可以想出如何计算出不选x物品时的方案数或者最大价值了。
g[j]=f[j]-g[j-v]
(因为g[j-v]可以表示为刚好选了x的方案数)

#include 
using namespace std;
typedef long long ll;
typedef pair pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=2000+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

int n,m;
int f[maxn],g[maxn];
int w[maxn];

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    f[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=m;j>=w[i];j--){
            f[j]=(f[j]+f[j-w[i]])%10;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            if(j

Tree

https://ac.nowcoder.com/acm/contest/140/E
也是用可撤销的套路,不过是对一棵子树撤销,还是有点厉害的

#include 
using namespace std;
typedef long long ll;
typedef pair pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=1e5+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

ll pow_mod(ll a,ll b){
    ll ret=1;
    while(b){
        if(b&1)ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}

int n,m;
struct edge{
    int to,nxt;
}e[maxn];
int head[maxn];
int tot;
void adde(int u,int v){
    e[tot].to=v;
    e[tot].nxt=head[u];
    head[u]=tot++;
}

struct node{
    ll d[11];
}dp[maxn];

node uni(node a,node b){
    node ret=a;
    for(int i=10;i>=2;i--){
        for(int j=1;j=1;i--){
                dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
            }
            ll t=b*pow_mod(val[a],mod-2)%mod;
            for(int i=1;i<=10;i++)dp[a].d[i]=(dp[a].d[i]*t)%mod;
            for(int i=1;i=1;i--){
                dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
            }
            for(int i=2;i=2;i--){
                dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
            }
            for(int i=1;i=1;i--){
                ans=uni(disuni(dp[line[i]],dp[line[i-1]]),ans);
            }
            ans=uni(dp[a],ans);
            printf("%lld\n",ans.d[b]);
        }
    }
    return 0;
}

5429 多重背包

http://codevs.cn/problem/5429/
用单调队列优化背包,就是对每个余数分开做,然后维护单调递减的队列即可。

#include 
using namespace std;
typedef long long ll;
typedef pair pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=7000+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

int n,m;

int v[maxn],w[maxn],c[maxn];
int dp[2][maxn];

pii que[maxn];

void work(int *f1,int *f2,int vv,int ww,int cc){
    for(int b=0;bhead&&cnt.se>=que[tail-1].se)tail--;
            que[tail++]=cnt;
            while(k-que[head].fi>cc)head++;
            f1[j]=que[head].se+k*ww;
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&v[i],&w[i],&c[i]);
        work(dp[i%2],dp[(i+1)%2],v[i],w[i],c[i]);
    }
    printf("%d\n",dp[n%2][m]);
    return 0;
}

你可能感兴趣的:(dp)