首页 > 其他分享 >AT_abc216_g [ABC216G] 01Sequence 题解

AT_abc216_g [ABC216G] 01Sequence 题解

时间:2024-03-07 13:33:57浏览次数:19  
标签:ch qu mathit int 题解 sum ABC216G now 01Sequence

分析

一道差分约束题。

我们令 \(\mathit{sum}_{i}\) 表示 \(1\) 到 \(i\) 中,\(1\) 的数量,根据题意可得:

  1. \(\mathit{sum}_{l_i-1}+x_i \le \mathit{sum}_{r_i}\)
  2. \(\mathit{sum}_{l+1} +(-1)\le \mathit{sum}_{l}\)
  3. \(\mathit{sum}_{l}+0 \le \mathit{sum}_{l+1}\)

因为我们要尽可能地使 \(1\) 的数量少,所以这是求不等式最小解。又因为边权有负,所以我们要跑 spfa 来求解,代码如下:

//sum[l-1]+x<=sum[r]
//sum[l]<=sum[r]
//sum[r]+(-1)<=sum[l]
#include<bits/stdc++.h>
using namespace std;
#define int long long
#pragma G++ optimize(2)
int n,m;
const int N=1e6+10;
int ne[N],e[N],h[N],w[N],idx;
inline void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
inline void read(int &x) {
	x=0;
	short flag=true;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	x*=flag;
}
int l,r,x;
int dis[N],vis[N];
inline void spfa(){
	memset(dis,-0x3f,sizeof(dis));
	queue<int> qu;
	qu.push(0),dis[0]=0,vis[0]=1;
	while(!qu.empty()){
		int now=qu.front();
		qu.pop();
		vis[now]=0;
		for(int i=h[now];~i;i=ne[i]){
			int j=e[i];
			if(dis[j]<dis[now]+w[i]){
				dis[j]=dis[now]+w[i];
				if(!vis[j]){
					vis[j]=1;
					qu.push(j);
				}
			}
		}
	}
}
signed main(){
	memset(h,-1,sizeof(h));
	read(n),read(m);
	for(register int i=1;i<=m;i++){
		read(l),read(r),read(x);
		add(l-1,r,x);
	}
	for(register int i=0;i<n;i++){
		add(i,i+1,0);
		add(i+1,i,-1);
	}
	spfa();
	for(register int i=1;i<=n;i++){
		printf("%lld ",dis[i]-dis[i-1]);//前缀和
	}
	return 0;
}

很显然,\(1 \le n,m \le 2 \times 10^5\),超时了。

我们考虑优化方法,可以使用正难则反的思想。如果我们我们令 \(\mathit{sum'}_{i}\) 表示 表示 \(1\) 到 \(i\) 中,\(0\) 的数量,那么再次根据题意就可以把上面的式子变成:

  1. \(\mathit{sum'}_{r_i}\le \mathit{sum'}_{l_i-1}+(r-l+1-x)\)
  2. \(\mathit{sum'}_{l+1} \le \mathit{sum'}_{l} +1\)
  3. \(\mathit{sum'}_{l} \le \mathit{sum'}_{l+1}+0\)

很显然,在我们需要 \(1\) 的数量最少时,该不等式方程组的解就需要最大,而所有的权值又是非负的,所以可以用 dijkstra 求出最短路。注意,求得的解是关于 \(\mathit{sum'}_{i}\) 的,所以我们需要进行取反。

代码

//sum[r]<=sum[l-1]+r-l+1-x
//sum[l]<=sum[l-1]+1
//sum[l-1]<=sum[l]+0
#include<bits/stdc++.h>
using namespace std;
#define int long long
#pragma G++ optimize(2)
#define PII pair<int,int>
#define x first
#define y second
int n,m;
const int N=1e6+10;
int ne[N],e[N],h[N],w[N],idx;
inline void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
inline void read(int &x) {
	x=0;
	short flag=true;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	x*=flag;
}
int l,r,x;
int dis[N],vis[N];
//inline void spfa() TLE
//	memset(dis,-0x3f,sizeof(dis));
//	queue<int> qu;
//	qu.push(0),dis[0]=0,vis[0]=1;
//	while(!qu.empty()){
//		int now=qu.front();
//		qu.pop();
//		vis[now]=0;
//		for(int i=h[now];~i;i=ne[i]){
//			int j=e[i];
//			if(dis[j]<dis[now]+w[i]){
//				dis[j]=dis[now]+w[i];
//				if(!vis[j]){
//					vis[j]=1;
//					qu.push(j);
//				}
//			}
//		}
//	}
//}
void dj(){
	memset(dis,0x3f,sizeof(dis));
	priority_queue<PII,vector<PII>,greater<PII> > qu;
	dis[0]=0,qu.push({dis[0],0});
	while(!qu.empty()){
		PII now=qu.top();qu.pop();
		if(vis[now.y]) continue;
		vis[now.y]=1;
		for(int i=h[now.y];~i;i=ne[i]){
			int j=e[i];
			if(dis[j]>now.x+w[i]){
				dis[j]=now.x+w[i];
				qu.push({dis[j],j});
			}
		}
	}
}
signed main(){
	memset(h,-1,sizeof(h));
	read(n),read(m);
	for(register int i=1;i<=m;i++){
		read(l),read(r),read(x);
        //add(l-1,r,x);
		add(l-1,r,r-l+1-x);
	}
	for(register int i=0;i<n;i++){
		//add(i,i+1,0);
		//add(i+1,i,-1);
        add(i,i+1,1);
		add(i+1,i,0);
	}
    //spfa();
	dj();
	for(register int i=1;i<=n;i++){
		printf("%lld ",(dis[i]-dis[i-1]==1?0:1));//取反,也可以用位运算
	}
	return 0;
}

标签:ch,qu,mathit,int,题解,sum,ABC216G,now,01Sequence
From: https://www.cnblogs.com/harmisyz/p/18058702

相关文章

  • CF1066E 题解
    Solution首先不难想到计算\(a\)的每一位对答案产生的贡献,然后题目告诉我们\(b\)每次会往右移一位,然后结合样例可以发现:对于\(a\)的第\(i\)位,能与其产生贡献的条件是:\(a_i=1\)且\(b_j=1(i\leqj)\),对答案的贡献不难想出即为\(2^{i-1}\times\sum\limits_{j=i}^{m}b_j......
  • AT_abl_e Replace Digits 题解
    分析线段树模板题。维护一个区间\([l,r]\)中\(\sum\limits_{i=l}^r10^{n-i}\)的答案。将某个区间\([l,r]\)全部修改成\(x\)之后的表示的数就是\(x\times(\sum\limits_{i=l}^r10^{n-i})\)。区间修改可以用线段树,用快速幂或者预处理弄出来\(10^x\),建树的时候就能把每......
  • AT_abl_d Flat Subsequence 题解
    分析线段树模板题。一眼DP。定义状态函数\(\mathit{f}_i\)表示前\(i\)个数中,必选\(\mathit{A}_i\)时\(B\)的最大长度。则有转移方程:\(\mathit{f}_i=\max\{f_j|((1\lej\lei-1)\land(-k\leA_i-A_j\lek))\}+1\)。答案就是\(\max\limits_{i=1}^{n}\mathit{f}_i......
  • CF808E 题解
    很好的一道分类讨论题。观察数据范围,\(w\leq3\),不难想到,将\(w\)分为\(1,2,3\)种情况,如果直接贪心选会不难发现是错的。但是如果\(w\)的值只有\(2\)种,就像\(w=1/2\)的情况,将\(w=1/2\)的数据按价值排序,最后枚举每种选多少即可。但是\(w=3\)就会显得难以处理,需要讨......
  • CF1824B1 LuoTianyi and the Floating Islands (Easy Version) 题解
    分析按照\(k\)的奇偶分开考虑。\(k\)为奇数。一个好的节点有且仅有一个在任意两个有人的节点\(i,j\)的路径的交点上的最优位置。若该交点偏移\(1\)步,则必然会使路径长度和\(+1\)。故期望为\(1\)。\(k\)为偶数。任意一个好的节点仍然在任意两个有人的节点\(i,j\)的......
  • 【教程】HBuilderX开发实践:隐私合规检测问题解决方案
    文章目录摘要引言正文1、违规收集个人信息2、APP强制、频繁、过度索取权限知识点补充总结 摘要本篇博客介绍了在使用HBuilderX进行开发过程中,常遇到的隐私合规问题,并提供了相应的解决方案。主要包括违规收集个人信息和APP强制、频繁、过度索取权限两方面。......
  • CF147B 题解
    Solution一道十分典型的dp题。有三个关键点分别是定义状态、优化和答案的统计。首先定义状态,定义\(f_{i,j,p}\)表示\(i\toj\)号节点,共走了不超过\(p\)条边,且是\(i\toj\)的最长路径。不超过\(p\)条边是为了方便转移,而最长路径如果都为负环,说明需要走更多的边,实......
  • P1503 鬼子进村 题解
    分析分块。我们定义\(\mathit{cnt}_i\)表示房子\(i\)是否出现过,\(\mathit{sum}_i\)表示在第\(i\)个块内没有被摧毁的房子数量,维护的房子是\((i-1)\timesS-1\)到\(i\timesS\),其中\(S=\sqrt{n}\)也就是块长。操作\(1\)。写一个栈,根据后进先出的特点,讲摧毁的房子......
  • ARC090E 题解
    Solution一道不错的计数题。因为直接求不相遇的方案十分复杂,所以考虑正难则反,用总的方案数减去相遇的方案数。求方案数很套路:在求最短路的时候开一个数组\(del\)记录到达点\(i\)的最短路条数,更新最短路时顺便更新即可。跑完最短路后,设\(dis1\)为\(s\)到\(t\)的最短路......
  • AT_abc256_h [ABC256Ex] I like Query Problem 题解
    分析用势能线段树。对于一段数字\(a_l\)到\(a_r\),每次全部除以一个大于\(1\)的数,不难发现最多除以\(\logx\)次就会使\(a_l\)到\(a_r\)全部变成\(0\),其中\(x\)是区间最大值。所以,在没有操作\(2\)的情况下,我们可以在每次操作\(1\)的时候都单点修改,只要在某个......