P14646 [POI 2025/2026 #1] 并非哈诺塔 / Hanoj
P14646 [POI 2025/2026 #1] 并非哈诺塔 / Hanoj
思路
容易得到,如果 \(1\) 所在的柱子是连着的数(或者只有一),就只需要将其他圆盘按顺序摆放即可。
但是一般不会出现这种情况,于是我们考虑清空一根柱子,然后再将 \(1\) 移过去。如何清空一根柱子?由于柱子上窄下宽,所以只要柱子 \(a\) 的下方比柱子 \(b\) 的上方要窄即可(要贪心找最少盘子的柱子 \(b\))。
赠送一组 hack:
6 4
2 1 6
1 2
2 3 5
1 4
7
4 2
1 4
2 4
3 4
2 4
3 4
1 4
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define freop(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define re register
#define endl '\n'
#define inf 0x7f7f7f7f
#define lb(x) ((x)&-(x))
#define pii pair<int,int>
#define piii pair<int,pair<int,int> >
#define fir first
#define sec second
#define thi second
#define debug() cerr << "debug "
const int N=1e6+1;
int n,m,id[N],f2;
bool f1=1;
vector<int> p[N];
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
cout.tie(0);
// freop("han");
//↑以上为初始化↑
//------------------------------
cin >> n >> m;
for(int i = 1,k;i<=m;++i){
cin >> k,p[i].resize(k),f2=(k?f2:i);
for(int j = 0;j<k;++j)
cin >> p[i][j],id[p[i][j]]=i;
}
for(int i = 0;i<p[id[1]].size()&&f1;++i)
f1&=(p[id[1]][i]==i+1);
if(f1){
cout << n-p[id[1]].size() << endl;
for(int i = p[id[1]].size()+1;i<=n;++i)
cout << id[i] << ' ' << id[1] << endl;
}else if(f2){
cout << n << endl;
for(int i = 1;i<=n;++i)
cout << id[i] << ' ' << f2 << endl;
}else{
pii mn={inf,0};
piii ans={inf,{0,0}},t;
for(int i = 1,t1,t2;i<=m;++i){
t1=p[i][0],t2=*(p[i].rbegin());
if(t1>mn.fir)
t={p[i].size(),{i,mn.sec}},
ans=(ans<t?ans:t);
if(mn.fir>t2) mn={t2,i};
}
mn={inf,0};
for(int i = m,t1,t2;i;--i){
t1=p[i][0],t2=*(p[i].rbegin());
if(t1>mn.fir)
t={p[i].size(),{i,mn.sec}},
ans=(ans<t?ans:t);
if(mn.fir>t2) mn={t2,i};
}
if(ans.fir==inf){cout << -1;return 0;}
cout << n+ans.fir << endl;
for(int i:p[ans.sec.fir]) id[i]=ans.sec.sec,cout << ans.sec.fir << ' ' << ans.sec.sec << endl;
for(int i = 1;i<=n;++i) cout << id[i] << ' ' << ans.sec.fir << endl;
}
return 0;
}

浙公网安备 33010602011771号