可撤銷揹包 與 單調隊列優化揹包

2287: 【POJ Challenge】消失之物

首先我們有f[]表示所有物品都考慮時的方案數或者最大價值。
使用g[j]表示不選x物品時總重量爲j的方案數或者價值最大值,就可以想出如何計算出不選x物品時的方案數或者最大價值了。
g[j]=f[j]-g[j-v]
(因爲g[j-v]可以表示爲剛好選了x的方案數)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> 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<w[i])g[j]=f[j];
            else{
                g[j]=(f[j]-g[j-w[i]]+10)%10;
            }
        }
        for(int j=1;j<=m;j++){
            printf("%d",g[j]);
        }
        printf("\n");
    }

    return 0;
}

Tree

https://ac.nowcoder.com/acm/contest/140/E
也是用可撤銷的套路,不過是對一棵子樹撤銷,還是有點厲害的

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> 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<i;j++){
            ret.d[i]=(ret.d[i]+ret.d[i-j]*b.d[j]%mod)%mod;
        }
    }
    return ret;
}

node disuni(node a,node b){
    node ret=a;
    for(int i=2;i<=10;i++){
        for(int j=1;j<i;j++){
            ret.d[i]=(ret.d[i]-ret.d[i-j]*b.d[j]%mod+mod)%mod;
        }
    }
    return ret;
}

ll val[maxn];
int fa[maxn];

int line[11];
int cc;

void dfs(int u){
    for(int i=head[u];i!=-1;i=e[i].nxt){
        int v=e[i].to;
        dfs(v);
        dp[u]=uni(dp[u],dp[v]);
    }
}

int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&val[i]);
        dp[i].d[1]=val[i];
    }
    for(int i=2;i<=n;i++){
        scanf("%d",&fa[i]);
        adde(fa[i],i);
    }
    dfs(1);
    int op,a,b;
    while(m--){
        scanf("%d%d%d",&op,&a,&b);
        cc=0;
        int ba=a;
        while(ba&&cc<10){
            line[cc++]=ba;
            ba=fa[ba];
        }
        if(op==0){
            for(int i=cc-1;i>=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<cc;i++){
                dp[line[i]]=uni(dp[line[i]],dp[line[i-1]]);
            }
            val[a]=b;
        }
        else if(op==1){
            for(int i=cc-1;i>=1;i--){
                dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
            }
            for(int i=2;i<cc;i++){
                dp[line[i]]=uni(dp[line[i]],dp[line[i-1]]);
            }
            cc=0;
            fa[a]=b;
            int ba=a;
            while(ba&&cc<10){
                line[cc++]=ba;
                ba=fa[ba];
            }
            for(int i=cc-1;i>=2;i--){
                dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
            }
            for(int i=1;i<cc;i++){
                dp[line[i]]=uni(dp[line[i]],dp[line[i-1]]);
            }
        }
        else if(op==2){
            if(cc==1){printf("%lld\n",dp[a].d[b]);continue;}
            node ans=disuni(dp[line[cc-1]],dp[line[cc-2]]);
            for(int i=cc-2;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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> 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;b<vv;b++){
        int head=0,tail=0;
        for(int k=0;k*vv+b<=m;k++){
            int j=b+k*vv;
            pii cnt=mp(k,f2[j]-k*ww);
            while(tail>head&&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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章