首页 > 其他分享 >ABC371 Review

ABC371 Review

时间:2024-09-15 16:24:05浏览次数:9  
标签:10 int Review ABC371 ans 区间 inline void

ABC371 Review

A

分类讨论题 ,过

B

模拟题,过

C

题意

给出一张原始图 \(G\) ,和一张待修改图 \(H\) ,每次对 \(H\) 进行一次操作可以花费相应的代价删除已经存在的一条边或者是添加未存在的边。

问使得两张图同构的最小代价 \(W\) 是多少。

思路

以为是什么高级的算法,但是又放在了 C 这个位置,又觉得是什么高深的结论,最后还是没有做出来。

其实注意到了 \(N\) 的值非常的小,考虑过暴力 dfs ,想了想好像不知道该怎么判断选出来的图是否和原图同构,于是就放弃开 D 题去了。

D

题意

给出 \(n\) 个二元组 \((x_i,p_i)\) ,其中 \(x_i\in[-10^9,10^9],p_i\in [0,10^9]\) 。有 \(m<2\times 10^5\) 个询问 ,每个询问给出一个 \([l,r]\) ,求出 \(\sum_i^{x_i\in[l,r]} p_i\) 的值。

思路

暴力跳显然是会超时的,然后数组的下标会出现负数,所以很自然的会想到离散化后再前缀和。

但是大可不必这么做,由于树状数组的复杂度是 \(\log n\) 的,所以完全可以直接前缀和。

这里不用开数组,直接用 unordered_map 代替数组就可以了,注意分左右两边统计。

Code

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=3e5;
template<typename T>inline void re(T &x)
{
	x=0;
	int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int n;
int maxr=-1,minl=1e9+7;
unordered_map<int,int> c1,c2;
inline int lowbit(int x){return x&(-x);}
inline void add1(int x,int v)
{
	for(;x<=1e9;x+=lowbit(x))	
		c1[x]+=v;
}
inline int query1(int x)
{
	int ans=0;
	for(;x>=1;x-=lowbit(x))ans+=c1[x];
	return ans;
}
inline void add2(int x,int v)
{
	for(;x<=1e9;x+=lowbit(x))	
		c2[x]+=v;
}
inline int query2(int x)
{
	int ans=0;
	for(;x>=1;x-=lowbit(x))ans+=c2[x];
	return ans;
}
int x[N],p[N];
int ans0;
inline void pre()
{
	re(n);
	for(register int i=1;i<=n;++i)re(x[i]),maxr=max(maxr,x[i]),minl=min(minl,x[i]);
	minl=-minl;
	for(register int i=1;i<=n;++i)
	{
		re(p[i]);
		if(x[i]>0)
			add1(x[i],p[i]);
		else if(x[i]<0) add2(-x[i],p[i]);
		else ans0=p[i];
	}
}
signed main()
{
	pre();
	int t;
	re(t);
	while(t--)
	{
		int l,r;
		re(l),re(r);
		if(l<0)
		{
			if(r<0)
				wr(query2(-l)-query2(-r-1));
			else if (r==0)wr(query2(-l)+ans0);
			else wr(query2(-l)+ans0+query1(r));
		}
		else if(l==0)
		{
			if(r==0)wr(ans0);
			else wr(ans0+query1(r));
		}
		else
		{
			wr(query1(r)-query1(l-1));	
		}
		putchar('\n');
	}
	return 0;
}

E

题意

给定序列 \({a_N}\) ,定义 \(f(l,r)\) 为 \([l,r]\) 区间内不同数字的种类数,求 \(\sum_{i=1}^n\sum_{j=i}^n f(i,j)\)

\(n\le2\times 10^5\)

思路

很显然,哪怕是我们能够去 \(O(n^2)\) 地统计 ,\(O(1)\) 地枚举,也是会超时的。

分开来考虑每个区间的贡献,如果一个区间包含 \(x\) ,不论个数,那么它就会对答案产生 \(1\) 的贡献。

这时候我们可以考虑转而枚举 \(x\) ,考虑在 \([1,n]\) 的范围内有多少个包含它的区间 ,那么就是 \(x\) 这个数对答案的贡献 $ans(x) $ 。

最后的答案就是 \(\sum_{x=1}^Nans(x)\) 。

进一步的,对于每一个 \(ans(x)\) ,都可以通过补集思想求出 ,也就是 \(ans(x)=C_{n}^2-\sum (\text{invalid})\),这一步可以在读入的时候就求出。

具体的,我们可以通过记录每一个数上一个出现的位置 \(las_{a[i]}\) ,那么对于 \(x\) 来说不合法的方案数就是 \([las_{a[i]}+1,i-1]\),注意最后要在 \(n+1\) 这个位置上面再对所有出现过的数字再用相同的方法统计一次。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6;
template<typename T>inline void re(T &x)
{
	x=0;
	int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
inline int c(int i){return i*(i-1)/2+i;}
int n,a[N],las[N];
int tmp;
signed main()
{
	cin>>n;
	int ans=0;
	int cnt=0;
	for(int i=1;i<=n;++i)
	{
		re(a[i]);
		if(!las[a[i]])cnt++;
		tmp+=c(i-las[a[i]]-1);
		las[a[i]]=i;
	}
	for(int i=1;i<=n;++i)
	{
		if(!las[i])continue;
		tmp+=c(n-las[i]);
	}
	wr(cnt*(c(n))-tmp);
//	cout<<endl;
//	for(int i=1;i<=n;++i)
	return 0;
}

延伸

对于去统计区间内不同数的种类,这道题是属于比较特殊的一种,因为会把全部的区间都给枚举完,所以我们可以从数学的角度来快速统计答案。但是如果现在不对所有区间进行询问,而是给出 \(q\) 个 \([l,r]\) 的询问,又该如何处理呢?

很容易想到莫队等一系列区间算法,加上树状数组求逆序对的启发,大可以搞一个权值树状数组的算法,题目链接如下 :

P1972 HH的项链

这道题会单独写一篇题解。

标签:10,int,Review,ABC371,ans,区间,inline,void
From: https://www.cnblogs.com/Hanggoash/p/18415335

相关文章

  • [ABC371D] 1D Country 线段树解法
    其实这题还可以用值域线段树来做的。。。考虑到\([-1e9,1e9]\)的数据范围,则一般的线段树绝对会MLE,但同时我们注意到点的个数只有\(2e5\)个,考虑使用动态开点线段树。即对于每个村庄,看做一个点,所以我们的线段树无需模拟满二叉树。由于\(log_2(2e9)\approx30\),所以我们的线......
  • 题解:AT_abc371_c [ABC371C] Make Isomorphic
    题目大意有两个简单无向图,你每一次可以给第二个图添上或去掉一条边,有相应花费,问将两个图变为同构最少需要花费多少钱。思路观察数据范围,可以发现NNN非常小,可以考虑枚......
  • [ABC371D] 1D Country 题解
    这题,怎么说呢,\(STL\)大法好。前置芝士:lower_pound函数在结构体上的使用。那其实这题便是一个二分前缀和的水题了。结构体存储每个村庄的距离\(x\),人口\(d\)。对于每个输入的\([l,r]\)二分查找其对应的村庄,进行一次答案的统计,输出即可。代码:#include<bits/stdc++.......
  • ABC371
    呜呜呜,第一次打完完整的ABC。才打了2000多名,太菜了。(A-Jiro十分简单,分讨即可。点击查看代码#include<iostream>#include<cstdio>usingnamespacestd;chara,b,c;intmain(){ cin>>a>>b>>c; if(a=='>'){ if(b=='>'){ if(c==&#......
  • 题解 [ABC371G] Lexicographically Smallest Permutation(中文/English)
    本题解提供英文版,位于示例代码之后。Englishversionofthiseditorialisprovidedafterthesamplecode.官方题解竟然用Python来算高精度lcm,我来提供一个可以避免一切大整数运算的方法。考察\(u\getsP_u\)这张图的每个置换环。为了使答案字典序最小,显然需要从前往后......
  • VS2022 17.12.0 Preview2版本对Copilot的功能增强
    前提条件,使用最新版的17.12.0Preview2,并且有有效的CopilotAI订阅,那么可以体验这些新鲜好用的功能增强了CopilotAI对IEnumerableVisualizer的可编辑表达式功能我们可以通过AI实现一些复杂的条件筛查,并且可以即时验证结果是否符合预期,对于开发和调试提供了极大的便利性......
  • ABC370 Review
    ABC370ReviewA模拟题,过B模拟题,过C很明显的贪心思路是把需要更改的字母分为两类:改大和改小。首先我们要明确的是要让输出的串尽量拥有小的字典序,且字典序比较的第一关键字是位置,第二是长度所以对于改小的部分,改的位置越靠前我们就放在越前面操作;对于改大的部分,改的位置......
  • 使用 nuxi preview 命令预览 Nuxt 应用
    title:使用nuxipreview命令预览Nuxt应用date:2024/9/8updated:2024/9/8author:cmdragonexcerpt:摘要:本文介绍了如何使用nuxipreview命令预览Nuxt.js应用,包括安装和准备环境、启动预览服务器的步骤,以及如何指定根目录和使用自定义.env文件等高级用法。通过nuxip......
  • J.U.C Review - ThreadLocal原理源码分析
    文章目录一致性问题一致性问题简介解决一致性问题的常见方法ThreadLocal什么是ThreadLocalThreadLocal的线程模型ThreadLocal的工作原理使用场景ThreadLocal的基本API1.构造函数`ThreadLocal()`2.初始化方法`initialValue()`3.访问器`get()`和`set()`4.......
  • J.U.C Review - 计划任务ScheduledThreadPoolExecutor源码分析
    文章目录TimeVSScheduledThreadPoolExecutor小DemoScheduledThreadPoolExecutor类结构ScheduledThreadPoolExecutor主要方法介绍scheduleDelayed接口ScheduledFuture接口RunnableScheduledFuture接口ScheduledFutureTask类scheduleAtFixedRatescheduleWithFixedDelayd......