Atcoder AGC011 题解

A - Airport Bus

贪心选择即可…

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
	int q=0;char ch=' ';
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
	return q;
}
const int N=100005;
int n,C,K,ans,sum,t,T[N];
int main()
{
	n=read(),C=read(),K=read();
	for(RI i=1;i<=n;++i) T[i]=read();
	sort(T+1,T+1+n);sum=C;
	for(RI i=1;i<=n;++i) {
		if(sum==C) ++ans,sum=1,t=T[i];
		else {
			if(T[i]-t<=K) ++sum;
			else ++ans,sum=1,t=T[i];
		}
	}
	printf("%d\n",ans);
	return 0;
}

B - Colorful Creatures

假如我们想让 i i i活下来,则你发现让一只别的生物去吃别的生物,新生物就非常难被它吃掉了,所以就让它一路吃上去即可。

我们从小生物到大生物考虑,假如前 i i i个生物里有 a n s ans ans个可以吞噬掉前 i i i个里面的所有生物,则看第 i + 1 i+1 i+1个生物,如果 ( ∑ j = 1 i a j ) ∗ 2 ≤ a i + 1 (\sum_{j=1}^i a_j)*2 \leq a_{i+1} (j=1iaj)2ai+1,则这 a n s ans ans个生物都不可能幸存,否则都可以,而 i + 1 i+1 i+1是一定可以的。

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
	int q=0;char ch=' ';
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
	return q;
}
typedef long long LL;
const int N=100005;
LL a[N];int n,ans;
int main()
{
	n=read();
	for(RI i=1;i<=n;++i) a[i]=read();
	sort(a+1,a+1+n);
	for(RI i=1;i<=n;++i) {
		a[i]+=a[i-1],++ans;
		if(a[i]+a[i]<a[i+1]) ans=0;
	}
	printf("%d\n",ans);
	return 0;
}

C - Squared Graph

看了一下官方题解。

就是说,假设有两张连通图 A A A B B B,满足假如在 A A A a a a a ′ a&#x27; a之间有边, B B B b b b b ′ b&#x27; b之间有边,则 C C C ( a , b ) (a,b) (a,b) ( a ′ , b ′ ) (a&#x27;,b&#x27;) (a,b)之间有边。原题对应 A = B A=B A=B的情况。

那么假如 A A A中从点 a a a l l l步可以走到点 a ′ a&#x27; a,在 B B B中走 l l l步也能从 b b b走到 b ′ b&#x27; b,那么在 C C C中, ( a , b ) (a,b) (a,b) ( a ′ , b ′ ) (a&#x27;,b&#x27;) (a,b)就是连通的。

如果 A A A中只有一个点,则 C C C的连通块数就是 B B B中点数。 B B B中只有一个点同理。

否则,可以发现,通过在一条边上走过去又走回来这个方法,可以走出无限种长度的路径,但是不能改变走出来的路径长度的奇偶性。

如果 A A A B B B都是二分图,则路径奇偶性无法改变,否则可以。所以两个图都是二分图时, C C C有两个连通块,否则有一个。

当然以上都是考虑连通图,所以我们只要对我们自己的图的每个连通块之间讨论一下即可。

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
	int q=0;char ch=' ';
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
	return q;
}
typedef long long LL;
const int N=100005,M=200005;
int n,m,tot,js,k1,k2,k3;LL ans;
int h[N],ne[M<<1],to[M<<1],col[N];
void add(int x,int y) {to[++tot]=y,ne[tot]=h[x],h[x]=tot;}
int dfs(int x,int c) {
	col[x]=c;int re=1;++js;
	for(RI i=h[x];i;i=ne[i])
		if(!col[to[i]]) {if(!dfs(to[i],3-c)) re=0;}
		else if(col[to[i]]!=3-c) re=0;
	return re;
}
int main()
{
	int x,y;
	n=read(),m=read();
	for(RI i=1;i<=m;++i) x=read(),y=read(),add(x,y),add(y,x);
	for(RI i=1;i<=n;++i) {
		if(col[i]) continue; js=0;
		if(dfs(i,1)) {
			if(js==1) ++k3;
			else ++k1;
		}
		else ++k2;
	}
	ans=2LL*k3*(n-k3)+1LL*k3*k3+2LL*k1*k1+2LL*k1*k2+1LL*k2*k2;
	printf("%lld\n",ans);
	return 0;
}

D - Half Reflector

一看就是手玩题。

首先如果整个序列最左端是A,则显然将它变成B即可。

否则手玩一下发现:

灵魂画手litble

这个操作可以看成,将整个序列全部取反,左移一位,最左的字母删除,在最右添加一个字母’A’。

那么可以用双端队列+打标记模拟,做到 O ( k ) O(k) O(k)

继续手玩,发现在丢了不超过 2 n 2n 2n个球后,如果 n n n为奇数,则序列会变成 A B A B A B . . . ABABAB... ABABAB...或者 B B A B A B . . . BBABAB... BBABAB...,并且这两种状态是循环发生的,最终状态是哪个和 k k k的奇偶性有关。如果 n n n为偶数,序列会变成 B A B A B A . . . BABABA... BABABA...并且不再发生变化。

#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int N=200005;
int n,K,tag,l,r,a[N*3];char S[N];
void print() {for(RI i=l;i<=r;++i) putchar(a[i]^tag?'A':'B');}
int main()
{
	scanf("%d%d",&n,&K);
	scanf("%s",S+1);
	for(RI i=1;i<=n;++i) a[i]=(S[i]=='A');
	l=1,r=n,tag=0;
	for(RI i=1;i<=n+n;++i) {
		if(a[l]^tag) a[l]^=1;
		else tag^=1,++l,a[++r]=tag^1;
		if(i==K) {print();return 0;}
	}
	if((n&1)&&(K&1)) a[l]^=1;
	print();
	return 0;
}

E - Increasing Numbers

任何一个上升数,可以写成9个全1数(0也算)的和。

l l l位上升数,可以写成 1 0 l + 1 − 1 9 \frac{10^{l+1}-1}{9} 910l+11

也就是说 ∑ i = 1 9 k 1 0 a i + 1 − 1 9 = n \sum_{i=1}^{9k} \frac{10^{a_i+1}-1}{9}=n i=19k910ai+11=n

∑ i = 1 9 k 1 0 a i + 1 = 9 n + 9 k \sum_{i=1}^{9k} 10^{a_i+1} =9n+9k i=19k10ai+1=9n+9k

9 n + 9 k 9n+9k 9n+9k的数位和要小于等于 9 k 9k 9k

可以发现最小的 k k k n n n的长度级别的,枚举即可。

#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int N=500005;
char s[N];int a[N<<1],n,sum;
int main()
{
	int x=0;
	scanf("%s",s+1);n=strlen(s+1);
	for(RI i=1;i<=n;++i) a[i]=(s[n-i+1]-'0')*9;
	for(RI i=1;i<=n;++i) a[i]+=x,x=a[i]/10,a[i]%=10;
	while(x) a[++n]=x%10,x/=10;
	for(RI i=1;i<=n;++i) sum+=a[i];
	for(RI i=1,j;;++i) {
		a[1]+=9,sum+=9,j=1;
		while(a[j]>9) {
			sum-=a[j+1],a[j+1]+=a[j]/10,sum+=a[j+1];
			sum-=a[j],a[j]%=10,sum+=a[j];
			++j;if(j>n) n=j;
		}
		if(sum<=9*i) {printf("%d\n",i);return 0;}
	}
	return 0;
}

F - Train Service Planning

orz这位dalao

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
	int q=0;char ch=' ';
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
	return q;
}
typedef long long LL;
const int N=100005;
int n,K,js;LL ans;
int a[N],b[N],L[N],R[N],c[N<<1],d[N<<3];LL s[N],f[N];
void GG() {puts("-1");exit(0);}
void pd(int i) {d[i<<1]=d[(i<<1)|1]=d[i],d[i]=0;}
int query(int x,int s,int t,int i) {
	if(s==t) return d[i];
	int mid=(s+t)>>1; if(d[i]) pd(i);
	if(x<=mid) return query(x,s,mid,i<<1);
	else return query(x,mid+1,t,(i<<1)|1);
}
void chan(int l,int r,int s,int t,int i,int v) {
	if(l>r) return;
	if(l<=s&&t<=r) {d[i]=v;return;}
	int mid=(s+t)>>1; if(d[i]) pd(i);
	if(l<=mid) chan(l,r,s,mid,i<<1,v);
	if(mid+1<=r) chan(l,r,mid+1,t,(i<<1)|1,v);
}
LL getf(int x) {
	int k=query(x,1,js,1);
	if(!k) return 0;
	return f[k]+(c[L[k]]%K-c[x]%K+K)%K;
}
int main()
{
	n=read(),K=read();
	for(RI i=1;i<=n;++i) {
		a[i]=read(),b[i]=read();
		s[i]=s[i-1]+a[i];
		if(b[i]==1&&a[i]+a[i]>K) {puts("-1");return 0;}
		//不同方向的列车走这条路的时间要不相交
	}
	for(RI i=n;i>=1;--i)
		if(b[i]==1) L[i]=(K-2LL*s[i-1]%K)%K,R[i]=(K-2LL*s[i]%K)%K;
		else L[i]=0,R[i]=K-1;
	for(RI i=1;i<=n;++i) c[++js]=L[i],c[++js]=R[i];
	sort(c+1,c+1+n+n);
	js=1;for(RI i=2;i<=n+n;++i) if(c[i]!=c[js]) c[++js]=c[i];
	for(RI i=n;i>=1;--i) {
		L[i]=lower_bound(c+1,c+1+js,L[i])-c;
		R[i]=lower_bound(c+1,c+1+js,R[i])-c;
		f[i]=getf(L[i]);
		if(L[i]>R[i]) chan(R[i]+1,L[i]-1,1,js,1,i);
		else chan(1,L[i]-1,1,js,1,i),chan(R[i]+1,js,1,js,1,i);
	}
	ans=1e18;
	for(RI i=1;i<=js;++i) ans=min(ans,getf(i));
	printf("%lld\n",ans+s[n]+s[n]);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值