Atcoder AGC050

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值