AT_abc277_h [ABC277Ex] Constrained Sums

  • 前言

    这道题就难在很难看出是一个 2-sat 因为它不像别的 2-sat 的题一样那么一眼。

    思路

    观察到 \(n\times m\leq 10^6\) 所以我们可以定义 \(2\times n\times m\) 个状态,我们发现如果定义成 \(d_{i,j}\) 表示 \(x_i\)\(j\) 是否可以那么就成一个 m-sat 了所以我们改一下状态,用 \(d_{i,j,0/1}\) 表示 \(x_i\geq j\) 是否可以满足条件,通俗一点就是当第三维是 \(0\)\(x_i\) 大于等于 \(j\) 可行,否则 \(x_i\) 必须小于 \(j\),所以这里我们只需要使 \(x_{i,0,1}\) 恒成立和 \(x_{i,m+1,0}\) 恒成立即可,随后我们就进行分类讨论。

    • 先不考虑条件,可以发现如果 \(d_{i,j,0}\) 可行那么 \(d_{i,j-1,0}\) 一定可行,所以对于所有的 \(d_{i,j,0}\) 都向 \(d_{i,j-1,0}\) 连一条边即可。

    • 对于 \(d_{i,j,1}\) 同理,如果它行(这里只要小于 \(j\))那么也一定要小于 \(j+1\)

    • 对于条件中,我们可以枚举一个 \(i\) 表示其中的一个数选什么,然后能够得到另一个能取的区间 \(l1\sim r1\)

    • 然后如果 \(i>r\) 那么当前点必须取小于的那一个,就是将 \(d_{x,i,0}\to d_{x,i,1}\),然后还有一种情况就是 \(i+m\leq l\) 那么小于 \(i\) 的一定不能选,就将 \(d_{x,i,1}\to d_{x,i,0}\)

    • 最后一种就是存在满足条件的情况,对于 \(r1\) 如果一方选 \(i\) 则另一方必须选小于等于 \(r1\) 的,即 \(d_{x,i,0}\to d_{y,r1+1,1}\) 以及 \(d_{y,r1+1,0}\to d_{x,i,1}\),对于 \(l1\) 我们发现如果一方取的数小于等于 \(i\) 则另一方必须大于等于 \(l1\) 就是 \(d_{x,i,1}\to d_{y,l1+1,0}\) 以及 \(d_{y,l1+1,1}\to d_{x,i,0}\)

    然后情况就考虑完了直接跑一遍 Tarjan 在输出 scc 小的即可。

    代码

    #include <bits/stdc++.h>
    #include<ext/pb_ds/assoc_container.hpp>
    #include<ext/pb_ds/tree_policy.hpp>
    #include <ext/rope>
    using namespace __gnu_pbds;
    using namespace std;
    #define int long long
    #define pb push_back
    #define rep(i,x,y) for(register int i=x;i<=y;i++)
    #define rep1(i,x,y) for(register int i=x;i>=y;--i)
    #define in(x) scanf("%lld",&x)
    #define fire signed
    #define il inline
    il void print(int x) {
    	if(x<0) putchar('-'),x=-x;
    	if(x>=10) print(x/10);
    	putchar(x%10+'0');
    }
    int T=1;
    const int N=1e4+10,M=1e2+10;
    int n,m,q;
    vector<int>v[N*M*2];
    int dfn[N*M*2],low[N*M*2];
    int is[N*M*2];
    stack<int>s;
    int idx;
    int val[N*M*2],tot;
    void tarjan(int x) {
    	s.push(x);
    	dfn[x]=low[x]=++idx;
    	is[x]=1;
    	for(auto to:v[x]) {
    		if(!dfn[to]) {
    			tarjan(to);
    			low[x]=min(low[x],low[to]);
    		} else if(is[to]) low[x]=min(low[x],dfn[to]);
    	}
    	if(low[x]==dfn[x]) {
    		tot++;
    		int p;
    		do{
    			p=s.top();
    			s.pop();
    			val[p]=tot;
    			is[p]=false;
    		}while(p!=x);
    	}
    }
    int get(int i,int j) {
    	return (i-1)*(m+2)+j+1;
    }
    void solve() {
    	in(n),in(m),in(q);
    	rep(i,1,n) {
    		v[get(i,0)+n*(m+2)].push_back(get(i,0));
    		v[get(i,m+1)].push_back(get(i,m+1)+n*(m+2));
    		rep(j,0,m+1) {//向前后连边
    			if(j<=m) v[get(i,j)+n*(m+2)].push_back(get(i,j+1)+n*(m+2));
    			if(j>=1) v[get(i,j)].push_back(get(i,j-1));
    		}
    	}
    	while(q--) {
    		int a,b,l,r;
    		in(a),in(b),in(l),in(r);
    		rep(i,0,m) {
    			int r1=min(m,r-i),l1=max(0ll,l-i+1);//判边界
    			if(i>r) {
    				v[get(a,i)].push_back(get(a,i)+n*(m+2));
    				v[get(b,i)].push_back(get(b,i)+n*(m+2));
    				continue;
    			}else {
    				v[get(a,i)].push_back(get(b,r1+1)+n*(m+2));
    				v[get(b,r1+1)].push_back(get(a,i)+n*(m+2));
    				v[get(b,i)].push_back(get(a,r1+1)+n*(m+2));
    				v[get(a,r1+1)].push_back(get(b,i)+n*(m+2));
    			}
    			if(i+m-1<l) {
    				v[get(a,i)+n*(m+2)].push_back(get(a,i));
    				v[get(b,i)+n*(m+2)].push_back(get(b,i));
    				continue;
    			}else {
    				v[get(a,i)+n*(m+2)].push_back(get(b,l1));
    				v[get(b,l1)+n*(m+2)].push_back(get(a,i));
    				v[get(b,i)+n*(m+2)].push_back(get(a,l1));
    				v[get(a,l1)+n*(m+2)].push_back(get(b,i));
    			}
    		}
    	}
    	rep(i,1,n*(m+2)*2) if(!dfn[i]) tarjan(i);
    	rep(i,1,n*(m+2)) {
    		if(val[i]==val[i+n*(m+2)]) {
    			cout<<"-1\n";
    			return ;
    		}
    	}
    	rep(i,1,n) {
    		rep1(j,m,0) {
    			if(val[get(i,j)]<val[get(i,j)+n*(m+2)]) {
    				cout<<j<<' ';
    				break;
    			}
    		}
    	}
    	return;
    }
    fire main() {
    	while(T--) {
    		solve();
    	}
    	return false;
    }
    
posted @ 2024-05-31 16:39  highkj  阅读(9)  评论(0)    收藏  举报