1 条题解

  • 0
    @ 2025-8-24 22:34:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ETHANK
    「我是星 我愿投身前途未卜的群星,为梦长明。」

    搬运于2025-08-24 22:34:54,当前版本为作者最后更新于2021-12-26 06:51:03,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目难度:USACO P+/NOI-

    子任务 1:T=1,N5000T=1,N\le 5000

    dp[i][j]dp[i][j] 为当前考虑到第 ii 头 H 牛,第 jj 头 G 牛时匹配的牛的最大权值和。那么我们可以选择不匹配 ii ,不匹配 jj ,或者是将 iijj 匹配。

    时间复杂度: O(N2)O(N^2)

    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define pii pair<int,int>
    #define vi vector<int>
    int main(){
    	T=read(),n=read(),K=read();
        vector <pii> cow[2];
        cow[0].pb({0,0}),cow[1].pb({0,0});
        rep(i,1,n){
            cin>>c;
            int x=read(),y=read();
            cow[c=='H'].pb({x,y});
            sum+=y;
        }
        A=sz(cow[0]),B=sz(cow[1]);
        if(T==1){
            vector <vi> dp(A+1,vi(B+1));
            rep(i,1,A)rep(j,1,B){
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                if(abs(cow[0][i].x-cow[1][j].x)<=K)
                    dp[i][j]=max(dp[i][j],dp[i-1][j-1]+cow[0][i].y+cow[1][j].y);
            }
            printf("%d\n",sum-dp[A][B]);
        }
    }
    

    子任务 2:T=2,N300T=2,N\le 300

    对于最大化未匹配的权值和,我们考虑使用类似的 dp 状态。但是注意到在上述转移时,有时候我们考虑的并不是最大匹配,只是因为最优解只产生于最大匹配(若不是最大匹配,多匹配两头牛显然更优),我们才能得到 T=1T=1 时的答案。

    于是我们需要把最大匹配这一限制加入我们的 dp 状态,具体地,我们加入一维 kk 表示最后一头未匹配的牛,假设我们不想匹配当前的 H 牛,那么牛 kk 必须满足如下条件之一:

    • kk 的品种是 HH
    • kk 与当前牛的距离大于 KK

    状态量是 O(N3)O(N^3) ,每次转移还是 O(1)O(1) 的,足够通过该子任务。

    时间复杂度:O(N3)O(N^3)

    vector <vector<vi>> dp(A+1,vector<vi>(B+1,vi(n+1,-1)));
    dp[0][0][n]=0;
    rep(i,0,A)rep(j,0,B)rep(k,0,n){
        if(dp[i][j][k]==-1)continue;
        if(i<A&&j<B&&abs(cow[0][i].x-cow[1][j].x)<=K)
            Max(dp[i+1][j+1][k],dp[i][j][k]);
        if(i<A&&(!(A<=k&&k<n&&cow[0][i].x<=cow[1][k-A].x+K)))
            Max(dp[i+1][j][i],dp[i][j][k]+cow[0][i].y);
        if(j<B&&(!(k<A&&cow[1][j].x<=cow[0][k].x+K)))
            Max(dp[i][j+1][A+j],dp[i][j][k]+cow[1][j].y);
    }
    int ans = 0;
    rep(i,0,n)Max(ans,dp[A][B][i]);
    printf("%d\n",ans);
    

    子任务 1:T=1,N5000T=1,N\le 5000

    考虑最终的优化,i,ji,j 两维比较难舍去,但我们可以修改最后一维的定义。定义 dp[i][j][x]dp[i][j][x] 为处理到前 ii 头 H 牛, jj 头 G 牛,并且钦定下一种不放入匹配的牛的品种为 xx 。有转移:

    $$dp[i][j][x]\to dp[i+1][j+1][x]\\ dp[i][j][H]\to dp[i+1][j][H]\\ dp[i][j][G]\to dp[i][j+1][G]\\ $$

    当然我们也可以转换钦定的品种:如果之前我们被强制不选 H 牛,那么最后一个未匹配的 H 牛最多是第 ii 个。能不放入匹配的 G 牛需要离该牛距离至少为 KK ,且在该牛之前的所有牛都要放入匹配。预处理出对于所有 ii ,满足条件的 G 牛编号的最小值,并且判断这段区间的牛是否能全部匹配即可。

    时间复杂度:O(N2)O(N^2)

    per(i,A,1)per(j,B,1){
        if(chk(i,j))lst[i][j]=lst[i+1][j+1]+1;
        else lst[i][j]=0;
    }
    int j=1;
    rep(i,1,A){
        while(j<=B&&(chk(i,j)||G[j].x<H[i].x))j++;
        nxtH[i] = j;
    }
    j=1;
    rep(i,1,B){
        while(j<=A&&(chk(j,i)||H[j].x<G[i].x))j++;
        nxtG[i] = j;
    }
    memset(f,-0x3f,sizeof(f));
    memset(g,-0x3f,sizeof(g));
    nxtG[0] = nxtH[0] = 1;
    f[0][0] = g[0][0] = 0;
    rep(i,0,A)rep(j,0,B){
        int cnt = max(nxtH[i]-j-1,0);
        if(i+cnt<=A && lst[i+1][j+1]>=cnt)
            Max(g[i+cnt][j+cnt],f[i][j]);
        cnt = max(nxtG[j]-i-1,0);
        if(j+cnt<=B && lst[i+1][j+1]>=cnt)
            Max(f[i+cnt][j+cnt],g[i][j]);
        if(i<A && j<B && chk(i+1,j+1)){
            Max(f[i+1][j+1],f[i][j]);
            Max(g[i+1][j+1],g[i][j]);
        }
        if(i<A) Max(f[i+1][j],f[i][j]+H[i+1].y);
        if(j<B) Max(g[i][j+1],g[i][j]+G[j+1].y);
    }
    printf("%d\n",max(f[A][B],g[A][B]));
    
    • 1

    信息

    ID
    7359
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者