1 条题解

  • 0
    @ 2026-5-2 16:52:59

    首先,如果拼接后的绳子绳结之间的距离是相等的,那么必然存在一个 dd 使得对于任意 ii 和任意 j2j \ge 2,都有 pi,jpi,j1=dp _ {i, j} - p _ {i, j - 1} = d,否则一定无解。

    下面的推导假设 dd 已经固定,若不存在 mi2m _ i \ge 2dd 不固定,这种情况会在之后提及。

    不妨设在答案中我们把第 aa 根和第 bb 根绳子拼在了一起,则此时 aa 的最右结点在整根拼好的绳子上的坐标就是前面绳子的长度+pa,ma{} + p _ {a, m _ a},而绳子 bb 的第一个结点就是 aa 前面的绳子长度+sa+pb,1{} + s _ a + p _ {b, 1}。如果这两个绳结之间的差 =d= d,那么 sa+pb,1pa,ma=ds _ a + p _ {b, 1} - p _ {a, m _ a} = d,也就是

    pb,1=pa,masa+dp _ {b, 1} = p _ {a, m _ a} - s _ a + d

    这就是若 bbaa 后面需要满足的条件。

    于是我们对于每一根绳子 ii,建一条 pi,1pi,misi+dp _ {i, 1} \to p _ {i, m _ i} - s _ i + d 的有向边。于是我们只需在图上找一条经过所有边的 Euler 路径或回路,那么就能找到答案了。如果找不到,就是无解。

    找 Euler 路径或回路可以用 Hierholzer 算法。

    接下来考虑 dd 不固定的情况。考虑找出一些 dd,并对于每个 dd 按上述方式建图判断,于是关键在于怎样找出数量尽可能少的 dd。观察上述的条件,发现若可能出现 Euler 路径或回路,则对于每个结点值 uu#{pi,1=u}\#\{p _ {i, 1} = u\}#{pi,misi+d=u}\#\{p _ {i, m _ i} - s _ i + d = u\} 的差,除了最多一个 11 和一个 1-1,剩下的必须是 00(若是 Euler 回路则必须全部是 00)。

    换句话说,起点可重集 {pi,1}i=1n\{p _ {i, 1}\} _ {i = 1} ^ n 和终点可重集 {pi,misi+d}i=1n\{p _ {i, m _ i} - s _ i + d\} _ {i = 1} ^ n 几乎完全相等,最多允许每个集合各多一个元素。不妨设 AA 表示排序后的起点可重集,BB 表示排序后的 {pi,misi}i=1n\{p _ {i, m _ i} - s _ i\} _ {i = 1} ^ n 可重集。那么若 A,BA, B 几乎完全相同,则大多数元素的配对满足 Ai=Bj+dA _ i = B _ j + d。也就是说合法的 dd 必然为一个 AA 中的元素减某个 BB 中的元素。

    允许最多各多一个的对齐方式非常受限,考虑从左往右对齐的过程:

    • 若最小的 A1A _ 1B1+dB _ 1 + d 恰好就能配对,那么 d=A1B1d = A _ 1 - B _ 1
    • A1A _ 1 恰好为多出来的那个,也就是没法配对,则 A2A _ 2 可能和 B1+dB _ 1 + d 配对,于是 d=A2B1d = A _ 2 - B _ 1
    • 也可能是 B1B _ 1 在最左边多出来,那么 A1A _ 1 可能和 B2+dB _ 2 + d 配对,于是 d=A1B2d = A _ 1 - B _ 2
    • 也可能 A1A _ 1B1B _ 1 都是多出来的,此时 d=A2B2d = A _ 2 - B _ 2

    对于右端也是类似的,实际上根本不需要额外考虑,因为情况完全对称。

    dd 固定,时间复杂度 O(nlogn)O(n \log n),不固定的话要乘上一个 k=4k = 4

    有点惊险过题,可能是因为人傻常数大。

    // Author: Azure_F.
    #include<iostream>
    #include<map>
    #include<vector>
    #include<utility>
    #include<cassert>
    #include<algorithm>
    #include<cstring>
    
    constexpr int N = 1e5 + 5;
    
    int n, s[N], p[N][2], u[N], v[N], a[N], b[N];
    
    int in[N << 1], out[N << 1];
    std::vector<std::pair<int, int> > G[N << 1];
    int ans[N], la = 0;
    
    bool used[N];
    void dfs(int u) {
    	while(!G[u].empty()) {
    		auto [v, id] = G[u].back(); G[u].pop_back();
    		if(!used[id]) used[id] = 1, dfs(v), ans[++la] = id;
    	}
    }
    
    inline bool _chk(int d) {
    	std::map<int, int> S;
    	for(int i = 1; i <= n; ++i) u[i] = p[i][0], v[i] = p[i][1] - s[i] + d;
    	for(int i = 1; i <= n; ++i) S[u[i]] = S[v[i]] = 1;
    	int l = 0; for(auto& [u, v] : S) v = ++l;
    	for(int i = 1; i <= n; ++i) {
    		G[S[u[i]]].emplace_back(S[v[i]], i);
    		++out[S[u[i]]], ++in[S[v[i]]];
    	}
    	int st = -1, ed = -1;
    	for(int i = 1; i <= l; ++i) {
    		if(out[i] - in[i] == 1) { if(!(~st)) st = i; else return false; }
    		else if(in[i] - out[i] == 1) { if(!(~ed)) ed = i; else return false; }
    		else if(in[i] ^ out[i]) return false;
    	}
    	if(!(~st)) for(int i = 1; i <= l; ++i) if(out[i]) { st = i; break; }
    	dfs(st); return !(la ^ n);
    }
    
    inline bool chk(int d) {
    	bool ret = _chk(d);
    	std::memset(in, 0, sizeof in);
    	std::memset(out, 0, sizeof out);
    	std::memset(used, 0, sizeof used);
    	for(int i = 0; i < (N << 1); ++i) G[i].clear();
    	return ret;
    }
    
    inline int Yes() { std::cout << "Yes\n"; for(int i = la; i >= 1; --i) std::cout << ans[i] << " "; return 0; }
    inline int No() { std::cout << "No\n"; return 0; }
    
    int main() {
    	std::ios::sync_with_stdio(false);
    	std::cin.tie(nullptr);
    	
    	int d = -1; std::cin >> n;
    	for(int i = 1; i <= n; ++i) {
    		int m, lp; std::cin >> m >> s[i];
    		for(int j = 1; j <= m; ++j) {
    			int _p; std::cin >> _p;
    			j == 1 ? p[i][0] = _p : 0; j == m ? p[i][1] = _p : 0;
    			if((~d) && j > 1 && _p - lp != d) return No();
    			else if(!(~d) && j > 1) d = _p - lp;
    			lp = _p;
    		}
    	}
    	
    	if(~d) return chk(d) ? Yes() : No();
    	else {
    		for(int i = 1; i <= n; ++i) a[i] = p[i][0], b[i] = p[i][1] - s[i];
    		std::sort(a + 1, a + n + 1); std::sort(b + 1, b + n + 1);
    		if(n == 1) return chk(a[1] - b[1]) ? Yes() : No();
    		const int d[4] = {a[1] - b[1], a[2] - b[1], a[1] - b[2], a[2] - b[2]};
    		for(int i = 0; i < 4; ++i) if(chk(d[i])) return Yes(); else la = 0;
    		return No();
    	}
    	
    	return 0;
    }
    
    • 1

    信息

    ID
    10279
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者