Atcoder AGC050

构建高效信息处理算法:线段树图、区间DP与状态转移

A
考虑到 10 ≈ log ⁡ 2 1000 10 \approx \log_2 1000 10log21000,每个页面向外连出两条边,要求任意两点距离不超过 10 10 10,因此建一颗类似于线段树的图。点 p p p 连向模意义下的点 2 p 2p 2p 2 p + 1 2p+1 2p+1 即可。
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

#include<iostream>
using namespace std;
int main(){
	int n,a,b;
	cin>>n;
	for(register int i=0;i!=n;i++){
		a=i<<1;
		b=a|1;
		if(a>n){
			a-=n;
		}else if(a==0){
			a=n;
		}
		if(b>n){
			b-=n;
		}
		cout<<a<<' '<<b<<endl;
	}
	return 0;
}

B
先找规律,看若某些格子上有硬币的情况是否有可能。
设共有 k k k 个位置有硬币,第 i i i 枚硬币在位置 p i p_i pi, S ( l , r ) S(l,r) S(l,r) 表示第 l l l 至第 r r r 枚硬币的集合。则 S ( 1 , k ) S(1,k) S(1,k) 可行的条件为存在三个正整数 a , b , c a,b,c a,b,c 满足:
a < b < c ⩽ k a<b<c \leqslant k a<b<ck
( b − a ) m o d    3 = ( c − b ) m o d    3 (b-a)\mod 3 =(c-b) \mod 3 (ba)mod3=(cb)mod3
a = 1 a=1 a=1 S ( 1 , a − 1 ) S(1,a-1) S(1,a1) 可行
a = b − 1 a=b-1 a=b1 S ( a + 1 , b − 1 ) S(a+1,b-1) S(a+1,b1) 可行
b = c − 1 b=c-1 b=c1 S ( b + 1 , c − 1 ) S(b+1,c-1) S(b+1,c1) 可行
c = k c=k c=k S ( c + 1 , k ) S(c+1,k) S(c+1,k) 可行
因此考虑区间DP。设 f i , j f_{i,j} fi,j 表示从位置 i i i 至位置 j j j 选一些位置放硬币的最大得分,且放置硬币的方案在该区间中可行。则DP转移为:
从区间 i , j i,j i,j 与区间 j + 1 , k j+1,k j+1,k 转移到区间 i , k i,k i,k
j − i m o d    3 = 2 j-i \mod 3 =2 jimod3=2,则从区间中选取 k k k 使得 k − i m o d    3 = 1 k-i \mod 3 =1 kimod3=1,并从区间 i + 1 , k − 1 i+1,k-1 i+1,k1 与区间 k + 1 , j − 1 k+1,j-1 k+1,j1 转移到区间 i , j i,j i,j
不难发现这样转移是完备的。
时间复杂度 O ( n 3 ) O(n^3) O(n3),空间复杂度 O ( n 2 ) O(n^2) O(n2)

#include<iostream>
using namespace std;
#define R register int
int f[500][500],a[500];
inline void Max(int&x,int y){
	x=x>y?x:y;
}
int main(){
	int n;
	cin>>n;
	for(R i=0;i!=n;i++){
		cin>>a[i];
	}
	for(R i=2;i!=n;i++){
		for(R j=0;i+j!=n;j++){
			for(R k=i+j;k!=j;k--){
				Max(f[j][i+j],f[j][k-1]+f[k][i+j]);
			}
			if(i%3==2){
				for(R k=j+1;k<i+j;k+=3){
					Max(f[j][i+j],f[j+1][k-1]+f[k+1][i+j-1]+a[j]+a[k]+a[i+j]);
				}
			}
		}
	}
	cout<<f[0][n-1];
	return 0;
}

C
若现有一确定的操作字符串,判断胜负情况。将字符串分为若干段,每一段S后都会有一个B,一段S的长度可能为 0 0 0。设状态 ( l , r ) (l,r) (l,r) 表示Snuke左侧有 l l l 个连续的空位,右侧有 r r r 个连续的空位,经过第一段S后状态为 ( + ∞ , + ∞ ) (+ \infin,+ \infin) (+,+),经过第一个B后状态变为 ( 0 , + ∞ ) (0,+ \infin) (0,+)。设当前状态为 ( 0 , r ) (0,r) (0,r),则又经过 b b bS和一个B之后的状态为 ( 0 , min ⁡ ( b , [ r 2 ] ) ) (0,\min(b,[\frac{r}2])) (0,min(b,[2r]))。由此归纳得若Snuke要赢则到倒数第 i i iS长度至少是 2 i − 2 2^{i-2} 2i2,其中 i > 1 i>1 i>1
根据结论定下DP状态,设 f i , j f_{i,j} fi,j 表示第 i i i 个位置可以为B且右侧的S为倒数第 j j j 段。显然 j ⩽ log ⁡ 2 n j \leqslant \log_2n jlog2n。设 i i i 右侧第一个B的位置为 l l l i + 2 j − 2 < l i+2^{j-2}<l i+2j2<l,则 f i , j = ∑ k = i + 1 l f k , j − 1 f_{i,j}= \sum_{k=i+1}^l f_{k,j-1} fi,j=k=i+1lfk,j1,前缀和优化DP即可。设第一个B的位置为 p p p,共 Q Q Q?,则答案为 2 Q − ∑ i = 1 p ∑ j = 1 f i , j 2^Q-\sum_{i=1}^p \sum_{j=1} f_{i,j} 2Qi=1pj=1fi,j。当原字符串不存在B时特殊处理,答案为 2 Q − 1 − ∑ i = 1 n ∑ j = 1 f i , j 2^Q-1-\sum_{i=1}^n \sum_{j=1} f_{i,j} 2Q1i=1nj=1fi,j。仔细处理边界情况。
时空复杂度 O ( n log ⁡ 2 n ) O(n \log_2n) O(nlog2n)

#include<iostream>
using namespace std;
#define R register int
#define P 998244353
int f[1000000][20],g[1000002][20];
inline int Add(int x,const int y){
	x+=y;
	return x<P?x:x-P;
}
int main(){
	string s;
	cin>>s;
	int n=s.length(),ans=1,l,t;
	bool tag=true;
	l=n;
	for(R i=n-1;i!=-1;i--){
		if(s[i]=='?'){
			ans<<=1;
			if(ans>P){
				ans-=P;
			}
		}
		if(s[i]!='S'){
			if(l==n){
				f[i][0]=1;
			}
			for(R j=0;j!=19;j++){
				t=i+(1<<j);
				if(t<l){
					f[i][j+1]=Add(g[t+1][j],P-g[l+1][j]);
				}
			}
		}
		if(s[i]=='B'){
			l=i;
			tag=false;
		}
		for(R j=0;j!=20;j++){
			g[i][j]=Add(f[i][j],g[i+1][j]);
		}
	}
	if(tag==true){
		ans--;
	}
	for(R i=0;i<=l;i++){
		for(R j=0;j!=20;j++){
			ans=Add(ans,P-f[i][j]);
		}
	}
	cout<<ans;
	return 0;
}

D
考虑影响答案的因素。比较显然的有执行的轮数,剩余人数,当前操作的人以及正在计算的人在人群中的排名。设 f p r e , s u f , r , p o s f_{pre,suf,r,pos} fpre,suf,r,pos 表示编号比当前正在计算的人编号小的有 p r e pre pre 人,编号大的有 s u f suf suf 人,正在执行了 r r r 轮,当前操作的人在人群中编号排名为 p o s pos pos。由于剩下的人抽中新的物品的概率 p p p 一定为 p r e + s u f + 1 + k − n k − r \frac{pre+suf+1+k-n}{k-r} krpre+suf+1+kn,DP转移考虑每种情况对参数的影响即可。
时空复杂度 O ( n 4 ) O(n^4) O(n4)

#include<iostream>
using namespace std;
#define R register int
#define L long long
#define P 998244353
inline int Add(int x,const int y){
	x+=y;
	return x<P?x:x-P;
}
int f[40][40][41][41],inv[41];
inline int GetAns(int pre,int suf,int r,int pos,int&n,int&k){
	int&g=f[pre][suf][r][pos];
	if(g!=-1){
		return g;
	}
	g=0;
	int tot=pre+suf+1,p,q;
	if(r==k||n-tot==k){
		return 0;
	}
	p=(L)(tot+k-n)*inv[k-r]%P;
	q=Add(P-p,1);
	if(pre+1==pos){
		g=((L)q*GetAns(pre,suf,r+(suf==0),suf==0?1:pos+1,n,k)+p)%P;
	}else if(pos>pre){
		g=((L)p*GetAns(pre,suf-1,r+(pos==tot),(pos-1)%(tot-1)+1,n,k)+(L)q*GetAns(pre,suf,r+(pos==tot),pos%tot+1,n,k))%P;
	}else{
		g=((L)p*GetAns(pre-1,suf,r,pos,n,k)+(L)q*GetAns(pre,suf,r,pos+1,n,k))%P;
	}
	return g;
}
int main(){
	putchar('1');
	inv[1]=1;
	int n,p;
	cin>>n>>p;
	for(R i=2;i<=p;i++){
		inv[i]=(L)(P-P/i)*inv[P%i]%P;
	}
	for(R i=0;i!=n;i++){
		for(R j=0;j!=n;j++){
			for(R k=0;k<=n;k++){
				for(R l=0;l<=n;l++){
					f[i][j][k][l]=-1;
				}
			}
		}
	}
	for(R i=2;i<=n;i++){
		printf("\n%d",GetAns(i-1,n-i,0,1,n,p));
	}
	return 0;
}

E
( a , b , c , d , e , f ) (a,b,c,d,e,f) (a,b,c,d,e,f) 表示是否存在自然数 x x x 使得 x m o d    b = a x \mod b=a xmodb=a x m o d    d = c x \mod d =c xmodd=c x m o d    f = e x \mod f=e xmodf=e。设 m i = g i + r i m_i=g_i+r_i mi=gi+ri,则答案为 ∑ i = 0 g 1 − 1 ∑ j = 0 g 2 − 1 ∑ k = 0 g 3 − 1 ( i , m 1 , j , m 2 , k , m 3 ) \sum_{i=0}^{g_1-1} \sum_{j=0}^{g_2-1} \sum_{k=0}^{g_3-1}(i,m_1,j,m_2,k,m_3) i=0g11j=0g21k=0g31(i,m1,j,m2,k,m3)。若存在素数 p p p 使得 p ∣ b p \mid b pb p ∤ d , f p \nmid d,f pd,f,则 ( a , b , c , d , e , f ) = ( a m o d    ( b p ) , b p , c , d , e , f ) (a,b,c,d,e,f)=(a \mod(\frac{b}{p}),\frac{b}p,c,d,e,f) (a,b,c,d,e,f)=(amod(pb),pb,c,d,e,f)。将此结论推广,若 p t 1 ∥ b , p t 2 ∥ d , p t 3 ∥ f p^{t_1} \parallel b,p^{t_2} \parallel d,p^{t_3} \parallel f pt1b,pt2d,pt3f,且 max ⁡ ( t 1 , t 2 ) ⩽ t 3 \max(t_1,t_2) \leqslant t_3 max(t1,t2)t3,设 f ′ = p max ⁡ ( t 1 , t 2 ) − t 3 f f'=p^{\max(t_1,t_2)-t_3}f f=pmax(t1,t2)t3f,则 ( a , b , c , d , e , f ) = ( a , b , c , d , e m o d    f ′ , f ′ ) (a,b,c,d,e,f)=(a,b,c,d,e \mod f',f') (a,b,c,d,e,f)=(a,b,c,d,emodf,f)。经过变换,可以使得 m 1 ∣ m 2 m 3 , m 2 ∣ m 1 m 3 , m 3 ∣ m 1 m 2 m_1 \mid m_2 m_3,m_2 \mid m_1 m_3,m_3 \mid m_1 m_2 m1m2m3,m2m1m3,m3m1m2
g = gcd ⁡ ( m 1 , m 2 , m 3 ) , m 1 = g a b , m 2 = g a c , m 3 = g b c , a ⩽ b ⩽ c g=\gcd(m_1,m_2,m_3),m_1=gab,m_2=gac,m_3=gbc,a \leqslant b \leqslant c g=gcd(m1,m2,m3),m1=gab,m2=gac,m3=gbc,abc。暴力模拟 2 , 3 2,3 2,3号信号灯的颜色变化,时间复杂度 O ( a + b ) O(a+b) O(a+b)。由于 a ⩽ b ⩽ b c ⩽ c , b c ⩽ g b c = m 3 a \leqslant b \leqslant \sqrt{bc} \leqslant c,bc \leqslant gbc=m_3 abbc c,bcgbc=m3。因此 a ⩽ b ⩽ m 3 a \leqslant b \leqslant \sqrt{m_3} abm3
时间复杂度 O ( g + r ) O(\sqrt{g+r}) O(g+r ),空间复杂度 O ( 1 ) O(1) O(1)

#include<iostream>
using namespace std;
#define R register int
#define L long long
#define I inline
#define P 998244353
I void Swap(L&x,L&y){
	L tem=x;
	x=y;
	y=tem;
}
I L Min(L x,L y){
	return x<y?x:y;
}
I void Compare(L&g1,L&m1,L&g2,L&m2){
	if(m1<m2){
		Swap(g1,g2);
		Swap(m1,m2);
	}
}
I L Gcd(L x,L y){
	return y==0?x:Gcd(y,x%y);
}
I L Calc(L m1,L m2,L m3){
	L v=m1/Gcd(m1,m2);
	v/=Gcd(v,m3);
	return m1/v;
}
I int Calc2(L l1,L r1,L l2,L r2,L g3,L m3){
	L l=l1>l2?l1:l2,r=Min(r1,r2);
	if(l>r){
		return 0;
	}
	int res=(r/m3%P*(g3+1)+Min(r%m3,g3)-(l-1)/m3%P*(g3+1)-Min((l-1)%m3,g3))%P;
	return res<0?res+P:res;
}
I int Solve(L g1,L m1,L g2,L m2,L g3,L m3){
	L v=Calc(m1,m2,m3);
	if(v!=m1){
		return(g1/v%P*Solve(v-1,v,g2,m2,g3,m3)+Solve(g1%v,v,g2,m2,g3,m3))%P;
	}
	v=Calc(m2,m1,m3);
	if(v!=m2){
		return(g2/v%P*Solve(g1,m1,v-1,v,g3,m3)+Solve(g1,m1,g2%v,v,g3,m3))%P;
	}
	v=Calc(m3,m1,m2);
	if(v!=m3){
		return(g3/v%P*Solve(g1,m1,g2,m2,v-1,v)+Solve(g1,m1,g2,m2,g3%v,v))%P;
	}
	Compare(g1,m1,g2,m2);
	Compare(g1,m1,g3,m3);
	Compare(g2,m2,g3,m3);
	L l1=0,l2=0,r1=g1,r2=g2;
	int res=0;
	while(l1!=l2||l1%m3!=0||l1==0){
		res+=Calc2(l1,r1,l2,r2,g3,m3);
		if(res>=P){
			res-=P;
		}
		if(r1<r2){
			l1+=m1;
			r1+=m1;
		}else{
			l2+=m2;
			r2+=m2;
		}
	}
	v=Gcd(m1,l1);
	m1/=v;
	l1/=v;
	v=Gcd(m2,l1);
	m2/=v;
	l1/=v;
	v=Gcd(m3,l1);
	m3/=v;
	l1/=v;
	return m1%P*(m2%P)%P*(m3%P)%P*res%P;
}
int main(){
	L g1,r1,g2,r2,g3,r3;
	cin>>g1>>r1>>g2>>r2>>g3>>r3;
	printf("%d",Solve(g1-1,g1+r1,g2-1,g2+r2,g3-1,g3+r3));
	return 0;
}
<think>首先,用户的问题是:“请问Atcoder 竞赛信息 编程比赛”,意思是询问关于AtCoder竞赛的信息和编程比赛。我需要基于系统级指令和用户可见层的要求来构建回答。 关键指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 - 参考提供的引用:引用[1]、[^2]、[^3]。 提供的引用: - 引用[1]: 介绍AtCoder平台,强调C++的使用,包括模板、STL、算法优化等。 - 引用[2]: 关于AtCoder初学者竞赛(AtCoder Beginner Contest),帮助初学者提高技能。 - 引用[3]: 介绍AC Library,一个用于AtCoder竞赛的工具,包括数据结构如线段树。 用户的问题是关于AtCoder竞赛的信息和编程比赛,所以我应该基于这些引用构建一个全面的回答。 回答结构: - **结构清晰**:我需要逐步引导用户。可能从介绍AtCoder开始,然后讨论竞赛类型,最后给出一些建议。 - **真实可靠**:使用提供的引用作为来源,确保信息准确。 - **生成相关问题**:在回答末尾添加相关问题。 - **引用标识**:在回答中自然地添加引用标识,如[^1]。 大纲回答: 1. **介绍AtCoder**:简要描述AtCoder是什么,基于引用[1]和[^2]。 2. **竞赛类型**:讨论AtCoder的竞赛,特别是初学者竞赛(ABC),基于引用[^2]。 3. **工具和库**:提到AC Library,基于引用[^3],因为它有助于竞赛。 4. **准备建议**:给出如何准备的建议,基于引用[1],如学习C++、算法等。 5. **生成相关问题**:在末尾添加相关问题。 数学表达式:用户的问题不直接涉及数学,但如果有必要,我可以引入一些数学概念。例如,在讨论算法时,可能提到时间复杂度或一些数学公式。但问题主要是关于信息性的,所以我应该避免不必要的数学。如果引入,确保使用正确的LaTeX格式。 例如: - 时间复杂度:$O(n \log n)$ - 或者一个简单的公式,如$f(x) = x^2$ 但保持相关。 最终回答结构: - 开头:直接回答用户的问题。 - 主体:分步骤解释。 - 结尾:总结并添加相关问题。 相关问题生成: - 基于主题,如如何参加AtCoder竞赛、推荐的学习资源、优化代码等。 - 例如: 1. 如何注册AtCoder账户? 2. 初学者应该从哪些竞赛开始? 3. 如何使用AC Library? 4. 常见的竞赛问题类型是什么? 确保回答是中文。</think>### AtCoder竞赛信息与编程比赛介绍 AtCoder是一个广受欢迎的在线编程竞赛平台,特别适合算法和编程爱好者参与。它起源于日本,现已发展为全球性的竞赛社区,尤其受到C++编程者的青睐。竞赛通常涉及解决算法问题,参与者需要在限定时间内编写高效代码来完成挑战。下面我将逐步介绍AtCoder的核心信息,帮助您快速入门。 #### 1. **AtCoder平台概述** AtCoder提供多种竞赛类型,从初学者到高级选手都有合适的赛事。平台强调算法优化和代码效率,竞赛问题常涉及数据结构、数学建模和动态规划等。例如,在时间复杂度的分析中,快速排序的平均时间复杂度为$O(n \log n)$,这体现了算法优化的重要性[^1]。关键特点包括: - **竞赛频率**:每周或每月都有定期赛事,如每周一次的AtCoder Beginner Contest(ABC),适合新手。 - **语言支持**:支持多种编程语言,但C++是最常用的,因为它能高效处理大规模数据;Python和Java也受欢迎。 - **评分系统**:基于解题速度和代码正确性评分,参与者通过排名提升技能。 引用来源:AtCoder是程序员喜爱的在线编程竞赛平台,尤其在C++社区中有很高的认可度。了解AtCoder的同时,掌握C++基础、编程技巧、竞赛相关知识是提升表现的关键[^1]。 #### 2. **主要竞赛类型** AtCoder的竞赛分为几个级别,初学者可从ABC开始: - **AtCoder Beginner Contest (ABC)**:专为新手设计,问题难度从简单到中等,覆盖基础算法和数据结构。例如,一个典型的ABC问题可能涉及数组排序或简单数学计算,如求解方程$x^2 + 2x + 1 = 0$的根[^2]。竞赛时长约100分钟,包含6-8道题。 - **AtCoder Regular Contest (ARC)**:中级竞赛,难度更高,适合有经验的选手,问题常涉及图论或组合数学。 - **AtCoder Grand Contest (AGC)**:高级赛事,挑战性强,问题需要高级算法如线段树或动态规划优化。 引用来源:AtCoder初学者竞赛是一个受欢迎的在线平台,旨在帮助初学者提高编程技能。本文介绍了关于AtCoder初学者竞赛的基本知识,并提供示例代码[^2]。 #### 3. **工具与资源推荐** 为提升竞赛效率,AtCoder提供了官方工具如AC Library: - **AC Library**:这是一个开源库,包含优化数据结构和算法(如线段树和字符串处理),能显著加速代码编写。例如,在解决区间查询问题时,使用线段树可将时间复杂度从$O(n)$优化到$O(\log n)$[^3]。 - **学习资源**:建议从AtCoder官方文档和社区论坛入手,结合C++ STL(标准模板库)练习。引用[1]提到,掌握模板、异常处理和版本控制是提升表现的关键。 - **实践建议**:初学者可先参加免费练习赛,使用在线IDE调试代码;逐步学习算法书籍或在线课程(如LeetCode或Codeforces的配套资源)。 引用来源:AC Library是AtCoder的官方编程竞赛武器,特别适用于算法竞赛环境下的高效编码。从字符串处理到数据结构如线段树的应用,AC Library提供了众多经过优化的工具[^3]。 #### 4. **准备与参与步骤** 参与AtCoder竞赛的简单步骤如下: 1. **注册账户**:访问[AtCoder官网](https://atcoder.jp/)免费注册。 2. **选择竞赛**:从ABC开始,逐步挑战ARC或AGC。 3. **赛前准备**:学习基础算法(如排序或搜索),使用C++编写模板代码;例如,快速排序的Python实现可作为参考(见下方代码)。 4. **赛中策略**:阅读问题描述,优先解决简单题;利用AC Library减少编码时间。 5. **赛后复盘**:分析排名和错误,社区讨论区提供反馈。 示例代码(快速排序,Python实现): ```python def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[0] left = [x for x in arr[1:] if x < pivot] right = [x for x in arr[1:] if x >= pivot] return quick_sort(left) + [pivot] + quick_sort(right) ``` 通过以上步骤,您能快速上手。AtCoder竞赛不仅提升编程技能,还能在算法面试中占优[^1]。 ### 相关问题 基于您的查询,以下是可能的相关问题,帮助深入探索: 1. 如何注册AtCoder账户并参加首次竞赛? 2. AtCoder初学者竞赛(ABC)的常见问题类型有哪些? 3. 如何使用AC Library优化代码性能? 4. 推荐哪些学习资源来准备AtCoder竞赛? 5. AtCoder竞赛的评分机制和排名系统如何工作?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值