luogu P16540 [EGOI 2026] 披萨大师 / Ovenmasters / QOJ18248 Ovenmasters 题解

link1 link2

我们把每个桌子上的披萨的排名放到值域上考虑。当一个桌子上的披萨要走到下一个披萨时,这两个披萨之间一定不能有其他披萨出现,也就是不能越过值域上的下一个披萨,所以会发现这些披萨在值域上的大小关系是不会改变的。

最朴素的想法是每次找到最小的能够往后走的披萨行动,但这样是 \(O(nm)\) 的。我们会发现当一个披萨往后走时,能够解放出来的披萨最多只有前面一个,所以我们从小到大移动披萨再递归到前面看是否能产生新的移动,这样字典序一定是最小的。时间复杂度线性。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,p[N];bool vis[N];
vector<int> b[N],ans;
void dfs(int x){
    while(p[x]<b[x].size()-1){
        if(x<=m&&b[x][p[x]+1]>b[x+1][p[x+1]])break;
        ans.push_back(b[x][++p[x]]);
        if(x>1)dfs(x-1);
    }
}
int main(){
    // freopen("oven.in","r",stdin);
    // freopen("oven.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int l;cin>>l;
        for(int j=1;j<=l;j++){
            int x;cin>>x;
            b[i].push_back(x);
            vis[x]=1;
            if(j>=2&&b[i][j-1]<b[i][j-2]){
                cout<<"NO\n";
                return 0;
            }
        }
    }
    for(int i=1;i<=m;i++)ans.push_back(b[i][0]);
    b[m+1].push_back(-1);
    for(int i=0;i<n;i++)
        if(!vis[i])
            b[m+1].push_back(i);
    sort(b+1,b+m+2,[&](vector<int> x,vector<int> y){return x[0]<y[0];});
    for(int i=1;i<=m+1;i++)dfs(i);
    for(int i=1;i<=m+1;i++)
        if(p[i]<b[i].size()-1){
            cout<<"NO\n";
            return 0;
        }
    cout<<"YES\n";
    for(int i:ans)cout<<i<<" ";
    return 0;
}
posted @ 2026-09-03 08:14  cqbzcjh  阅读(3)  评论(0)    收藏  举报