【题解】AGC056C 差分约束 思维 建模
好题,考察了对差分约束较深的理解。
首先限制区间 内恰好有 个 ,可以考虑将限制转化为前缀和数组上的限制,即 ,又因为前缀和本身的限制关系 ,可以得出一个差分约束的关系:
直接将等于边拆成大于小于边做差分约束求字典序最小的 ,因为有负权边会被卡成 。
考虑将等号代表的关系使用一个代表元表示(),这样可以避免掉上面的负权边,但是第二类边可能会出现 移项得到 在 时同样会出现负权边。
考虑如何避免负权边,之所以会出现负权边是因为第一类的传递关系中会涉及到量的改变,我们试图建立一种直接的等价类关系来描述第一类关系:
考虑式子拆开成一个左侧只和 相关右侧只和 相关的等式:,这样我们就把传递关系改成了一种等价关系,定义 ,则上面三个式子分别变成了:
(当然还有 ,这个条件会在后面的差分约束中天然被满足)
所以直接将所有第一种关系相同的 用同一个变量 表示,然后对所有代表变量解决差分约束问题。
同样的,我们只需要最小化 的字典序就可以最小化 的字典序,直接 bfs 跑差分约束即可,因为我们求的是字典序最小解,所以一定不会出现 的情况,复杂度线性。
代码:(为方便使用了并查集进行缩等价类,复杂度会多一个 )
#include<bits/stdc++.h>
#define ll long long
#define all(x) x.begin(),x.end()
#define rep(i,x,y) for(auto i(x);i<=(y);++i)
#define Rep(i,x,y) for(auto i(x);i>=(y);--i)
using namespace std;
const int N = 1e6 + 20 ;
int n , m , x[N] , fa[N] , ptr ;
vector <int> ed[N] ;
inline int find (int x) {
while (x ^ fa[x]) x = fa[x] = fa[fa[x]] ;
return x;
}
signed main ( ) {
ios :: sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
cin >> n >> m ; iota (fa,fa+n+1,0);
rep (i,1,m) {
int l , r ; cin >> l >> r ; -- l ;
int gl = find (l) , gr = find (r) ;
if(fa[gl] ^ gr) fa[gl] = gr ;
}
rep (i,1,n) {
ed[find(i)].emplace_back (find(i - 1)) ;
ed[find(i - 1)].emplace_back (find(i)) ;
}
memset(x,-1,sizeof x); x[find(0)] = 0;
vector <int> q = {find(0)} ;
while (ptr < (int)q.size( )) {
int u = q[ptr ++];
for (int v : ed[u]) {
if (!~x[v]) {
x[v] = x[u] + 1 ;
q.emplace_back(v) ;
}
}
}
rep (i,1,n)
if (x[find(i)] > x[find(i - 1)])
cout << 0 ;
else
cout << 1 ;
return 0 ;
}
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970898,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步