首页 > 其他分享 >AtCoder Beginner Contest 256

AtCoder Beginner Contest 256

时间:2022-09-27 11:02:30浏览次数:73  
标签:AtCoder le Beginner 10 int 线段 long times 256

AtCoder 五十连练 第二练

AtCoder Beginner Contest 256

D - Union of Interval

给定 \(N\) 个左闭右开的区间,求这些区间的并集。

数据范围:\(1 \le N \le 2 \times 10^5\)。

Code.

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int st[N],n,cnt,mx;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int l,r; scanf("%d%d",&l,&r); mx=max(mx,r);
		st[l]++; st[r]--;
	}
	for(int i=1;i<=mx;i++)
	{
		if(cnt == 0 && st[i]) cout<<i<<" ";
		if(st[i] < 0 && cnt+st[i] == 0) cout<<i<<endl;
		cnt+=st[i];
	}
	return 0;
}

E - Takahashi's Anguish

一共有 \(N\) 个人,编号从 \(1\) 到 \(N\)。

高桥决定选择一个序列 \(P=(P_1,P_2,...,P_N)\),这是一个从 \(1\) 到 \(N\) 的整数的排列,并按照这个顺序给 \(P_1,P_2,...,P_N\) 人一个糖果。

由于第 \(i\) 号人不喜欢第 \(X_i\) 号人,如果高桥先给第 \(X_i\) 号人糖果,那么第 \(i\) 号人会有 \(C_i\) 的挫折感;否则,第 \(i\) 号人的挫败感为 \(0\)。

高桥可选择任意序列 \(P\),使他们的挫折感的最小可能总和是多少?

数据范围:\(2 \le N \le 2 \times 10^5,1 \le C_i \le 10^9\)。

我们可以从人 \(i\) 向他讨厌的第 \(X_i\) 号人连边,发现图构成了一颗基环树,显然产生矛盾的情况为他们在一个环上,链不会对答案造成贡献,我们需要破环成链,考虑一步贪心,我们可以选择环上最小的那个点将他计入贡献,有向边,所以是强连通分量所有大于 \(1\) 的分量中最小那个点计入答案, \(tarjan\) 缩点即可,注意开 long long,时间复杂度 \(O(n+m)\) ,要我说可以把数据规模拉到 \(10^6\),时限开小一点,把那些非正解暴力 \(O(n \log n)\) 的并查集全部干碎。

Code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int n,h[N],ne[N<<1],e[N<<1],idx,w[N],sz[N],mn[N],scc_cnt,stk[N],top,dfn[N],low[N],in_stk[N],nowstep,res;
void add(int u,int v) {ne[++idx]=h[u],e[idx]=v,h[u]=idx;}
void tarjan(int u)
{
	dfn[u]=low[u]=++nowstep; stk[++top]=u; in_stk[u]=1;
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
		if(! dfn[j]) {tarjan(j); low[u]=min(low[u],low[j]);}
		else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
	}
	if(low[u] == dfn[u])
	{
		++scc_cnt; int y;
		do
		{
			y=stk[top--]; in_stk[y]=0;
			mn[scc_cnt]=min(mn[scc_cnt],w[y]);
			sz[scc_cnt]++;
		} while(y != u);
	}
}
signed main()
{
	memset(h,-1,sizeof h); memset(mn,0x7f,sizeof mn);
	scanf("%lld",&n);
	for(int i=1,x;i<=n;i++) {scanf("%lld",&x); add(i,x);}
	for(int i=1;i<=n;i++) scanf("%lld",w+i);
	for(int i=1;i<=n;i++) if(! dfn[i]) tarjan(i);
	for(int i=1;i<=scc_cnt;i++) {if(sz[i] == 1) continue ; res+=mn[i];}
	printf("%lld\n",res);
	return 0;
}

F - Cumulative Cumulative Cumulative Sum

atcoder 的题是不是对取模有特别的执着?

写一个数据结构,支持单点修改,查询原数列的前缀和的前缀和的前缀和,对 \(998244353\) 取模。

数据范围:\(1 \le N \le 2 \times 10^5\)。

\(\begin{aligned} d_{i} &=(1+2+\cdots+i) a_{1}+(1+2+\cdots+(i-1)) a_{2}+\cdots+a_{i} \\ &=\sum_{j=1}^{i} \frac{(i-j+1)(i-j+2)}{2} a_{j} \\ &=\frac{1}{2}\left(\sum_{j=1}^{i} j^{2} a_{j}-(2 i+3) \sum_{j=1}^{i} j a_{j}+(i+1)(i+2) \sum_{j=1}^{i} a_{j}\right) \end{aligned}\)

我们只需要开三个树状数组同时维护 \(a_i,a_i \times i,a_i \times i^2\) 就可以了,对了,还有一个 \(2\) 的逆元。

Code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10,mod=998244353;
int n,q,inv=499122177,a[N],t1[N],t2[N],t3[N];
int lowbit(int x) {return x&-x;}
void modify(int *tr,int x,int k) {if(x <= 0) return ; for(int i=x;i<N;i+=lowbit(i)) tr[i]=(tr[i]+k)%mod;}
int query(int tr[],int x) {int res=0; for(int i=x;i;i-=lowbit(i)) res=1ll*(res+tr[i])%mod; return res%mod;}
void add(int x,int y) {modify(t1,x,y); modify(t2,x,x*y%mod); modify(t3,x,x*x%mod*y%mod);}
signed main()
{
	scanf("%lld%lld",&n,&q);
	for(int i=1;i<=n;i++) scanf("%lld",a+i),add(i,a[i]);
	while(q -- )
	{
		int op,x,v; scanf("%lld",&op);
		if(op == 1)
		{
			scanf("%lld%lld",&x,&v);
			add(x,-a[x]); a[x]=v; add(x,a[x]);
		}
		else
		{
			scanf("%lld",&x); int res=(x+1)*(x+2)%mod*query(t1,x)%mod;
			res=(res-(2*x+3)%mod*query(t2,x)%mod+mod)%mod; res=(res+query(t3,x))%mod; res=res*inv%mod;
			printf("%lld\n",(res+mod)%mod);
		}
	}
}

G - Black and White Stones

矩阵快速幂优化 dp ,好题,不想写了。挖个坑回来补。


Ex - I like Query Problem

好题,让你写个数据结构,同时支持区间推平,区间整除,查询区间和,这是个裸的势能线段树,但我珂朵莉树上头,写了个珂朵莉树套线段树维护,具体思路在 luogu 的这个 讨论 里了,复杂度应该是正确的吧,这个操作可以叫珂朵莉树二次在线吧

理论上就是珂朵莉树用来维护区间权值相等的极大块,再写一颗有区间推平的线段树辅助查询,均摊复杂度应该在两只 \(\log\) 左右,常数大,作为有 区间推平 操作的势能线段树的下位替代品,可以说是用珂朵莉树来简化修改,或者说是用线段树来优化查询了?

优点可能是少去了原本在线段树上分析势能的操作,比较无脑且好写吧。比较好玩,回来可以单独发篇博客?

数据范围:\(1 \le N \le 5 \times 10^5\)。

Code.

#include<bits/stdc++.h>
#define int long long
inline char gc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read()
{
	int x=0; char c=gc(); bool f=0;
	for(;c<'0'||c>'9';c=gc()) f|=(c=='-');
	for(;c>='0'&&c<='9';c=gc()) x=(x<<1)+(x<<3)+(c^48);
	return x=f ? -x : x;
}
using namespace std;
const int N=5e5+10;
int n,q,a[N],tt; struct Seg {int l,r,sum,tag;} tr[N<<2];
inline void pushup(int u) {tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;}
inline void pushdown(int u)
{
	if(tr[u].tag != -1)
	{
		tr[u<<1].sum=tr[u].tag*(tr[u<<1].r - tr[u<<1].l + 1);
		tr[u<<1|1].sum=tr[u].tag*(tr[u<<1|1].r - tr[u<<1|1].l + 1);
		tr[u<<1].tag=tr[u<<1|1].tag=tr[u].tag;
	}
	tr[u].tag=-1;
}
inline void build(int u,int l,int r)
{
	tr[u].l=l,tr[u].r=r,tr[u].tag=-1;
	if(l == r) return tr[u].sum=a[l],void();
	int mid = (l + r) >> 1ll;
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
	pushup(u);
}
inline int query(int u,int l,int r)
{
	if(l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
	pushdown(u);
	int mid = (tr[u].l + tr[u].r) >> 1ll,res=0;
	if(l <= mid) res=query(u<<1,l,r); if(mid < r) res+=query(u<<1|1,l,r);
	return res;
}
inline void modify(int u,int l,int r,int k)
{
	if(l <= tr[u].l && tr[u].r <= r)
	{
		tr[u].sum=k*(tr[u].r - tr[u].l + 1);
		tr[u].tag=k; return ;
	}
	pushdown(u);
	int mid = (tr[u].l + tr[u].r) >> 1ll;
	if(l <= mid) modify(u<<1,l,r,k); if(mid < r) modify(u<<1|1,l,r,k);
	pushup(u);
}
struct node
{
	int l,r; mutable int v;
	bool operator < (const node &o) const {
		return l < o.l;
	}
} t[N]; set<node> s;
inline set<node> :: iterator split(int pos)
{
	auto it=s.lower_bound(node{pos,-1,0});
	if(it->l == pos && it != s.end()) return it;
	it -- ; int l=it->l,r=it->r,v=it->v;
	s.erase(it); s.insert(node{l,pos-1,v});
	return s.insert(node{pos,r,v}).first;
}
inline void assign(int l,int r,int v)
{
	auto itr=split(r+1),itl=split(l);
	s.erase(itl,itr); s.insert(node{l,r,v});
	modify(1,l,r,v);
}
inline void qr(int l,int r,int x)
{
	auto itr=split(r+1),itl=split(l); int pl=0,yl=1;
	for(auto it=itl;it!=itr;it++) it->v/=x,t[++pl]=*it;
	s.erase(itl,itr);
	for(int i=2;i<=pl;i++)
	{
		if(t[i].v == t[yl].v) t[yl].r=t[i].r;
		else t[++yl]=t[i];
	}
	for(int i=1;i<=yl;i++)
	{
		s.insert(node{t[i].l,t[i].r,t[i].v});
		modify(1,t[i].l,t[i].r,t[i].v);
	}
}
signed main()
{
	n=read(); q=read();
	for(int i=1,l=1;i<=n;i++)
	{
		a[i]=read(); if(i == 1) tt=a[i];
		else if(a[i] != tt || i == n)
		{
			s.insert(node{l,i-1,tt});
			l=i,tt=a[i];
		}
	}
	s.insert(node{n,n,a[n]}); build(1,1,n);
	while(q -- )
	{
		int op=read(),l=read(),r=read();
		if(op == 1) qr(l,r,read()); 
		else if(op == 2) assign(l,r,read());
		else printf("%lld\n",query(1,l,r));
	}
	return 0;
}

标签:AtCoder,le,Beginner,10,int,线段,long,times,256
From: https://www.cnblogs.com/EastPorridge/p/16733794.html

相关文章

  • AtCoder Beginner Contest 270 G,Ex
    y1s1,G和Ex在推等比数列式子上是相似的。G前置知识:BSGS(其实就是根号讨论)首先我们展开这个递归式:\[X_{i}\equivA^{i}S+\sum_{j=0}^{i-1}A^jB\modP\]感觉第一项有......
  • Atcoder试题乱做 Part2
    感受下来,思维难度有参差,所以还是可以做的,虽然有的题和中国赛题差距有点大,但是无伤大雅?新的\(\text{Part}\)我要自己做出来更多题!\(\text{[AGC014D]Blackan......
  • Atcoder试题乱做 Part4
    时光怎不经一生浮浮沉沉已半生一壶浊酒欲随风一步一瞥似惊鸿情字要如何追问一指兰花为谁挽留\(\text{[ARC147D]SetsScores}\)\(\color{green}{\text{[EASY]}}\)......
  • Atcoder试题乱做 Part3
    最后一年了,一年不到,为了可爱的学长们,为了自己,要拼命了啊.\(\text{[AGC048D]PockyGame}\)\(\color{green}{\text{[EASY]}}\)怎么这都做不出来,废物啊.显然石......
  • P2569 [SCOI2010]股票交易 题解
    设\(f_{i,j}\)表示第1天至第\(i\)天,手上有\(j\)股股票时拥有的最多钱。考虑转移,首先就有\(f_{i,j}=-j\timesap_i\)即单纯买入,然后由转移方程定义有\(f_{i,j}=......
  • AtCoder Beginner Contest 270
    AtCoder五十连练第一练AtCoderBeginnerContest270A-1-2-4Test考试有三道题,分别是\(1\)分、\(2\)分、\(4\)分。高桥、青木和Snuke参加了这次考试。高桥得......
  • AtCoder Beginner Contest 270
    A.1-2-4Test水题。B.Hammer分裂讨论。codeC.Simplepath一遍dfs就完了,怎么还有这种搜索题!codeD.Stones观察数据范围,\(O(NK)\)可过。\(dp_i\)表示\(i\)......
  • AtCoder Beginner Contest 270
    咕咕咕。D-Stones冲了发贪心,然后WA。然后想了个DP,就令\(dp_{n,0/1}\)表示石头总数为\(n\)时,先手/后手最多能拿多少个石头,然后跑个\(O(nk)\)的DP就完事了。......
  • AtCoder Beginner Contest 268(D-E)
    D-UniqueUsername 题意:给出n个字符串,以任意顺序排列,然后在每两个字符串中间加最少一个"_",然后给出m个字符串,问是否能得出一个字符串,不在这m个字符串中,并且长度在3-16......
  • AtCoder Beginner Contest 043 题解
    欢迎来到我的算法小屋前言 TaskNameAChildrenandCandies(ABCEdit)BUnhappyHacking(ABCEdit)CBeTogetherDUnbalancedA1)题目描述2......