Luogu

LOJ

分析

感觉同步赛上的我就是个 SB /kk

下面没有证明。

为了方便我们把所有 $d_i$ 从小到大排序。

先考虑 $m=n-1$ 的情况。此时显然会有 $d_1< k,d_1+d_n\geq k$,于是我们可以把 $d_1$ 和 $d_n$ 放在一起做一道菜,这样子变成了 $n'=n-1,m'=m-1$ 的情况。所以我们只要每次把最少的和最多的拿出来即可。

再考虑 $m\geq n$ 的情况。此时显然会有 $d_n\geq k$,于是我们可以拿 $d_n$ 单独做一道菜,这样子就转化为了 $n'=n/n-1,m'=m-1$ 的情况(前者是 $d_n=k$,后者是 $d_n>k$)。如果到最后都只出现了第一种情况,说 明 $n=m$ 且 $d_i=k$,显然可以构造出解;否则最后一定可以转化为 $m=n-1$ 的情况。

最后考虑 $m=n-2$ 的情况。可以发现,如果我们能把集合划分成两个部分 $S$ 和 $T$,满足 $\sum_{i\in S}d_i=(|S|-1)k$,则可以转化为两个 $m=n-1$ 的部分解决,否则无解。我们把式子转化为 $\sum_{i\in S}(d_i-k)=-k$,于是相当于 01 背包,std::bitset 优化一下即可做到 $\mathcal{O}(\frac{n^2k}{\omega})$。

实现时可以用 std::multiset 来维护 $d_i$。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
#define mp make_pair
using namespace std;
typedef long long ll;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=500+10,M=5000+10;

int n,m,k,d[N];

void solve(int n,int m,multiset<pair<int,int>> S,vector<pair<int,int>> ans[]) {
    for (int i=1;i<=m;++i) ans[i].clear();
    int cnt=0;
    while (m>S.size()-1) {
        auto x=*S.rbegin(); S.erase(--S.end());
        ans[++cnt].emplace_back(mp(x.second,k));
        x.first-=k; if (x.first) S.insert(x);
        --m;
    }
    while (m) {
        auto x=*S.begin(),y=*S.rbegin();
        S.erase(S.begin()),S.erase(--S.end());
        ans[++cnt].emplace_back(mp(x.second,x.first));
        ans[cnt].emplace_back(mp(y.second,k-x.first));
        y.first-=k-x.first; if (y.first) S.insert(y);
        --m;
    }
}

namespace Yui {
    vector<pair<int,int>> ans[M];
    multiset<pair<int,int>> S;
    void main() {
        S.clear();
        for (int i=1;i<=n;++i) S.insert(mp(d[i],i));
        solve(n,m,S,ans);
        for (int i=1;i<=m;++i) {
            for (auto j:ans[i]) printf("%d %d ",j.first,j.second);
            puts("");
        }
    }
}

namespace Ui {
    vector<pair<int,int>> ansx[M],ansy[M];
    multiset<pair<int,int>> S,T;
    bitset<5000001> dp[N];
    void main() {
        for (int i=0;i<=n;++i) dp[i].reset();
        dp[0][2500000]=1;
        for (int i=1;i<=n;++i) {
            if (d[i]>k) dp[i]=dp[i-1]|(dp[i-1]<<(d[i]-k));
            else dp[i]=dp[i-1]|(dp[i-1]>>(k-d[i]));
        }
        if (!dp[n][2500000-k]) { puts("-1"); return; }
        S.clear(),T.clear();
        for (int i=n,x=2500000-k;i;--i) {
            if (x-d[i]+k>=0&&x-d[i]+k<=5000000&&dp[i-1][x-d[i]+k])
                S.insert(mp(d[i],i)),x-=d[i]-k;
            else T.insert(mp(d[i],i));
        }
        solve(S.size(),S.size()-1,S,ansx);
        solve(T.size(),T.size()-1,T,ansy);
        for (int i=1;i<=S.size()-1;++i) {
            for (auto j:ansx[i]) printf("%d %d ",j.first,j.second);
            puts("");
        }
        for (int i=1;i<=T.size()-1;++i) {
            for (auto j:ansy[i]) printf("%d %d ",j.first,j.second);
            puts("");
        }
    }
}

int main() {
    int T=read();
    while (T--) {
        n=read(),m=read(),k=read();
        for (int i=1;i<=n;++i) d[i]=read();
        if (m==n-2) Ui::main();
        else Yui::main();
    }
    return 0;
}
最后修改:2020 年 08 月 22 日 07 : 00 PM