AtCoder Grand Contest 011

Atcoder 专栏收录该内容
10 篇文章 0 订阅

A - Airport Bus

从后往前贪心即可。

#include<bits/stdc++.h>
using namespace std;

const int N=100010;
int a[N],n,c,k;

int main(){
	scanf("%d %d %d",&n,&c,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	int tot=1,now=a[n],ans=0;
	for(int i=n-1;i>=1;i--){
		if(now-a[i]>k || tot==c) ans++,tot=1,now=a[i];
		else tot++;
	}
	if(tot) ans++;
	printf("%d\n",ans);
}

B - Colorful Creatures

二分即可

#include<bits/stdc++.h>
using namespace std;

const int N=100010;
int a[N],n;

bool check(int x){
	long long tot=0;
	for(int i=1;i<=x;i++) tot+=a[i];
	for(int i=x+1;i<=n;i++)
		if(tot*2<a[i]) return false;
		else tot+=a[i];
	return true;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	int l=1,r=n,ans=0;
	while(l<=r){
		int mid=(l+r)/2;
		if(check(mid)) r=(ans=mid)-1;
		else l=mid+1;
	}
	printf("%d\n",n-ans+1);
}

C - Squared Graph

对于两个联通块而言,若两者都不存在奇环才会在新图上表示为两个联通块。
记录下之前出现的(有奇环/没奇环)的联通块个数,暴力计算即可。
单点特殊讨论下。

#include<bits/stdc++.h>
using namespace std;

const int N=100010;
struct edge{
	int y,nex;
}s[N<<2];
int n,m,first[N],vis[N],d[N],len;
bool op=false;

void ins(int x,int y){
	s[++len]=(edge){y,first[x]};first[x]=len;
}

void dfs(int x,int ty){
	vis[x]=ty;
	for(int i=first[x];i!=0;i=s[i].nex){
		int y=s[i].y;
		if(vis[y]!=-1){
			if(vis[y]!=(ty^1)) op=false;
		}
		else dfs(y,ty^1);
	}
}

int main(){
	scanf("%d %d",&n,&m);
	int x,y,t[2],tot=0;t[0]=t[1]=0;
	long long ans=0;
	for(int i=1;i<=m;i++)
		scanf("%d %d",&x,&y),ins(x,y),ins(y,x),d[x]++,d[y]++;
	memset(vis,-1,sizeof(vis));
	for(int i=1;i<=n;i++) if(vis[i]==-1){
		if(d[i]==0) {tot++;continue;}
		op=true;dfs(i,0);
		ans+=op+1;
		if(op) ans+=2*(2*t[1]+t[0]);
		else ans+=2*(t[1]+t[0]);
		t[op]++;
	}
	ans+=1ll*tot*tot+2ll*tot*(n-tot);
	printf("%lld\n",ans);
}

D - Half Reflector

很好的思维题。
首先如果第一个是 A A A,那么会将这个变成 B B B
考虑 B B B A A A B B B BBBAAABBB BBBAAABBB的交界处,会变成 A A B B B A A A A AABBBAAAA AABBBAAAA。也就是翻转,然后循环往前挪了一位。
这个显然何时都有效。
那么我们就清楚了每次的操作大致是什么样的。
首先特判 n = 1 n=1 n=1
可以发现经过 O ( n ) O(n) O(n)次操作之后,最后一位操作完肯定是 A A A,每次挪位都会翻转,可以发现每个位置上的值只跟奇偶性有关, n n n为偶数的时候。最后会变成 B A B A B A . . . B A BABABA...BA BABABA...BA,奇数的时候会在两个状态之间反复横跳,然后就可以很轻易得出答案了。

#include<bits/stdc++.h>
using namespace std;

const int N=200010;
char s[N];
int a[N];
int k,n;

int main(){
	scanf("%d %d",&n,&k);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++) a[i]=s[i]-'A';
	int t=0,beg=1;
	if(n&1){
		int tot=0;
		for(int i=2;i<=n;i++) if(a[i]^a[i-1]) tot++;
		if(a[1]^a[n]) tot++;
		while(k){
			if(a[beg]==t){
				if(a[beg]^a[(beg+n-2)%n+1]) tot--;
				if(a[beg]^a[beg%n+1]) tot--;
				a[beg]^=1;
				if(a[beg]^a[(beg+n-2)%n+1]) tot++;
				if(a[beg]^a[beg%n+1]) tot++;
			}
			else beg=beg%n+1,t^=1;
			k--;
			if(a[beg]==t && tot==n-1 && a[beg]==a[(beg+n-2)%n+1]) break;
		}
		if(k&1) a[beg]^=1;
	}
	else{
		int tot=0;
		for(int i=2;i<=n;i++) if(a[i]^a[i-1]) tot++;
		if(a[1]^a[n]) tot++;
		while(k){
			if(a[beg]==t){
				if(a[beg]^a[(beg+n-2)%n+1]) tot--;
				if(a[beg]^a[beg%n+1]) tot--;
				a[beg]^=1;
				if(a[beg]^a[(beg+n-2)%n+1]) tot++;
				if(a[beg]^a[beg%n+1]) tot++;
			}
			else beg=beg%n+1,t^=1;
			k--;
			if(a[beg]==(t^1) && tot==n) break;
		}
	}
	for(int i=beg;i<=n;i++) printf("%c",'A'+(a[i]^t));
	for(int i=1;i<beg;i++) printf("%c",'A'+(a[i]^t));
}

E - Increasing Numbers

这个上升数显然可以划分成若干个连续 1 1 1的加法,假设分成的最小连续 1 1 1数量为 K K K,那么答案即为 ⌈ K 9 ⌉ \lceil \frac K 9\rceil 9K
简单的转化 N = ∑ i = 1 K 1 0 x − 1 9 9 N + K = ∑ i = 1 K 1 0 x N=\sum_{i=1}^K \frac{10^x-1}{9}\\ 9N+K=\sum_{i=1}^K 10^x N=i=1K910x19N+K=i=1K10x
两边显然 m o d    9 \mod 9 mod9同余,所以我们只需要保证 9 N + K 9N+K 9N+K的数位和不超过 K K K即可。
显然答案不会超过数位个数 ∗ 9 *9 9,每次暴力 + 1 +1 +1判断即可。
由于 + 1 +1 +1是均摊 O ( 1 ) O(1) O(1)的,所以时间复杂度正确。

#include<bits/stdc++.h>
using namespace std;

const int N=500010;
char s[N];
int a[N],n;

int main(){
	scanf("%s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++) a[i]=s[n-i+1]-'0',a[i]*=9;
	int t=0;
	for(int i=1;i<=n;i++) if(a[i]>9){
		a[i+1]+=a[i]/10;
		a[i]%=10;
		if(i==n) n++;
	}
	for(int i=1;i<=n;i++) t+=a[i];
	int ans=0;
	while(1){
		if(t<=ans) break;
		a[1]++;ans++;t++;
		for(int i=1;i<=n;i++) if(a[i]>9){
			t-=a[i];
			a[i+1]+=a[i]/10;
			t+=a[i]/10;
			a[i]%=10;
			t+=a[i]%10;
			if(i==n) n++;
		}
		else break;
	}
	printf("%d\n",(ans+8)/9);
}

F - Train Service Planning

题太长了,人都读傻了还做?
跳了跳了

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值