1. 程式人生 > 實用技巧 >AtCoder Beginner Contest 188題解

AtCoder Beginner Contest 188題解

A

題意

\(x,y\)相差是否小於\(3\)

#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
 
ll x,y;
 
int main(){
	scanf("%lld%lld",&x,&y);
	if(abs(y - x) < 3)
	puts("Yes");
	else
	puts("No");
}

B

題意

問兩個向量的內積是否為\(0\)
照著題目模擬就行

#include<iostream>
#include<cstdio>
#define ll long long
 
ll n,a[10000006],b[10000006];
 
int main(){
	scanf("%lld",&n);
	for(int i = 1;i <= n;++i)
	scanf("%lld",&a[i]);
	ll sum = 0;
	for(int i = 1;i <= n;++i){
		scanf("%lld",&b[i]);
		sum += a[i] * b[i];
	}
	if(sum == 0)
	puts("Yes");
	else
	puts("No");
}

C

題意

\(2^n\)個人進行樹狀比賽,問最後獲得第二名的人是誰
用類似於線段樹的建樹,最後對根節點\(1\)的兩個子節點進行判斷(比較的時候用鍵值,樹上存的是編號)

#include<iostream>
#include<cstdio>
#define ll long long
#define mid ((l + r) >> 1)
 
ll n,a[1000005];
int val[(1000005) << 2];
 
void build(int now,int l,int r){
	if(l == r){
		val[now] = l;
		return ;
	}
	build(now * 2,l,mid);
	build(now * 2 + 1,mid + 1,r);
	if(a[val[now * 2]] > a[val[now * 2 + 1]])
	val[now] = val[now * 2];
	else
	val[now] = val[now * 2 + 1];
	return;
} 
 
int main(){
	scanf("%lld",&n);
	n = (1 << n);
	for(int i = 1;i <= n;++i)
	scanf("%lld",&a[i]);
	build(1,1,n);
	if(val[1] == val[2])
	std::cout<<val[3];
	else
	std::cout<<val[2];
}

D

題意

\(Takahashi\) 出去遊玩,現在提供了\(n\)個專案,時間是\([a_i, b_i]\),這些專案每天分別需要花費\(c_i\),但它可以選擇一天花費\(C\)元玩這天所有可玩專案,專案出現了他就一定要玩,求他的最少花費
考慮離散化,在離散後的陣列上打差分標記,再對當前的錢數進行一個字首和,對每一段判斷是否取\(C\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long 
 
ll n,C;
 
ll a[200005],b[200005],c[200005],cnt;
ll num[800005],mark[800005];
 
unsigned ll now = 0,ans = 0;
 
int main(){
	scanf("%lld%lld",&n,&C);
	ll sum = 0;
	ll vsum = 0;
	for(int i = 1;i <= n;++i){
		scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
		num[++cnt] = a[i];
		num[++cnt] = b[i] + 1;
	} 
	std::sort(num + 1,num + cnt + 1);
	cnt = std::unique(num + 1,num + cnt + 1) - num - 1;
	for(int i = 1;i <= n;++i){
		mark[std::lower_bound(num + 1,num + cnt + 1,a[i]) - num] += c[i];
		mark[std::lower_bound(num + 1,num + cnt + 1,b[i] + 1) - num] -= c[i];
	}
	num[0] = num[1] + 1;
//	for(int i = 1;i <= cnt;++i)
//	std::cout<<num[i]<<" "<<mark[i]<<std::endl; 
	now = mark[1];
	for(int i = 2;i <= cnt;++i){
		//std::cout<<" "<<num[i - 1]<<" "<<num[i]<<" "<<now<<std::endl; 
		if(now <= C)
		ans += (now) * (num[i] - num[i - 1]);
		else
		ans += C * (num[i] - num[i - 1]);
		now += mark[i];			
	}
	std::cout<<ans<<std::endl;
}

E

題意

有向圖,有點權,你可以在一個點上用點權買一塊黃金,在再另一塊你能到達的點上以點權賣出,問必須進行一次買賣的最大收益
我原本是進行一次\(dfs\)這樣處理每個點的字首最小值,但這樣會在環上跑\(2\)次,我也這樣\(T\)了一發
我們可以考慮按照點權的大小優先\(dfs\)這樣最算有環也只用跑\(1\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
 
ll n,m,cnt,ans = -0x3f3f3f3f;
ll head[200005];
ll val[200005],maxx[200005],minn[200005];
int vis[200005];
 
struct K{
	ll val,num;
}p[200005];
 
struct P{
	ll to,next;
}e[400005];
 
void add(ll x,ll y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
 
void dfs(ll now){
	//std::cout<<now<<" "<<val[now]<<" "<<minn[now]<<std::endl;
	ans = std::max(val[now] - minn[now],ans);
	for(int i = head[now];i;i = e[i].next){
		if(!vis[e[i].to]){
		minn[e[i].to] = std::min(minn[now],val[now]);
		vis[e[i].to] ++ ; 
		dfs(e[i].to);
		}
	}
}
 
bool operator < (K a,K b){
	return a.val < b.val;
}
 
int main(){
	memset(maxx,-0x3f,sizeof(maxx));
	memset(minn,0x3f,sizeof(minn));
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= n;++i)
	scanf("%lld",&p[i].val),p[i].num = i,val[i] = p[i].val;
	for(int i = 1;i <= m;++i){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		add(x,y); 
	}
	std::sort(p + 1,p + 1 + n);
	for(int i = 1; i<= n;++i)
	if(!vis[p[i].num])
	dfs(p[i].num);
	std::cout<<ans<<std::endl;
}

F

題意

\(x,y\),可以對\(x做+1,-1,*2\)的操作請問最少幾次能到\(y\)
考慮進行記憶化搜尋,以後這種沒有太好思路的題都可以往搜尋想

#include<iostream>
#include<cstdio>
#include<map>
#define ll long long

using std::map;

ll x,y;

map<ll,ll>QWQ;

ll solve(ll y){
	if(y <= x) return x - y;
	if(QWQ.count(y)) return QWQ[y];
	ll ans = y - x;
	if(y % 2) ans = std::min(ans,1 + std::min(solve(y - 1),solve(y + 1)));
	else
	ans = std::min(ans,1 + solve(y / 2));
	return QWQ[y] = ans;
}

int main(){
	scanf("%lld%lld",&x,&y);
	std::cout<<solve(y);
}