AtCoder Beginner Contest 194 A~E題解


A - I Scream

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

int main() 
{
	Angel_Dust;
	int A,B;cin >> A >> B;
	A += B;
	if(A >= 15 && B >= 8)	return cout << "1\n",0;
	else if(A >= 10 && B >=3)	return cout << "2\n",0;
	else if(A >= 3)	return cout << "3\n",0;
	else cout << "4\n";
	return 0;
}

B - Job Assignment

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 1005;
int a[N],b[N];

int main() 
{
	Angel_Dust;
	int n;cin >> n;
	forn(i,1,n)	cin >> a[i] >> b[i];
	
	int res = a[1] + b[1];
	forn(i,1,n)	res = min(res,a[i] + b[i]);
	forn(i,1,n)	forn(j,1,n) if(i != j)	res = min(res,max(a[i],b[j]));
	printf("%d\n",res);
	return 0;
}

C - Squared Error

經典套路:拆平方和變成\(\sum\limits_{i = 2}^{n}\sum\limits_{j = 1}^{i - 1}(A_i ^ 2 + A_j^2 - 2 * (A_i + A_j))\)再拆和式分別維護前綴和/前綴平方和即可計算。

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 3e5+7;
ll sum[N],ssum[N],a[N];

int main() 
{
	Angel_Dust;
	int n;cin >> n;
	forn(i,1,n)	cin >> a[i];
	forn(i,1,n)	sum[i] = sum[i - 1] + a[i],ssum[i] = ssum[i - 1] + a[i] * a[i];
	
	ll res = 0;
	forn(i,2,n)
	{
		res += (i - 1) * (a[i] * a[i]);
		res += ssum[i - 1];
		res -= 2 * a[i] * sum[i - 1];
	}
	printf("%lld\n",res);
	return 0;
}

D - Journey

直接求期望是比較困難的。因為按普通套路來看的話這個題如果做dp轉移的話大概寫成:\(f[x]\)表示使\([1,x]\)中所有點聯通的期望,但是這個狀態轉移不了,因為你根本不能從維度信息得到除了\([1,x]\)之外的點是否是聯通的。考慮把問題本身降維一下:問題等價於每次在\([1,n]\)之內抽一個數,獨立且等概率,求每個數至少出現一個的期望抽取次數。本身期望是不太好求的,但是可以拆解一下問題:設\(f[x]\)表示當前已經抽到了\(x - 1\)種數,再抽一個不同的數的期望。那么對於:抽到了\(x\)種數再抽一種不同這個事件來說,他的概率是:\((n - x + 1) / n\)。符合幾何分布,期望是概率的倒數。接下來根據題目的定義:\(f[1]\)應該是\(0\)特殊處理。對於答案:\(ans = \sum f[i]\)。求和統計即可。

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

int main() 
{
	int n;cin >> n;
	double res = 0;
	forn(i,1,n - 1)	res += double(n) / i;
	printf("%.18lf\n",res);
	return 0;
}

E - Mex Min

區間求mex是個比較吊比的問題,不太合理。這個題的一個特點就是每次移動區間實際上只會刪除一個元素以及增加一個元素。先暴力求出第一個區間的答案,后續考慮移動區間的同時維護答案。每次暴力推mex肯定不可接受,那么方向顯然就是想mex怎么移動:假設刪除元素產生了一個空的點,這個點如果位置比上一個答案更左,那么顯然這個空的位置將會是新的mex。反過來如果沒有出現新的空位,或者空位的位置大於上次mex的位置,這時就不能直接說答案會是某個點了。

我的代碼直接選擇暴力推mex,雖然過了但是我覺得復雜度是假的,之后會對這個問題補上。

UPD:else while的一行可以刪掉。因為題目求的是所有區間里面mex的最小值,所以如果答案不會變的更小,那么更新mex是毫無意義的,我們只關心會變得更小的可能性。就沒有復雜度一類的問題了。

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)	
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 2e6+7;
int a[N],cnt[N];

int main() 
{
	int n,m;scanf("%d%d",&n,&m);
	forn(i,1,n)	scanf("%d",&a[i]);
	int mex = 0,res = 0;
	forn(i,1,m)	++cnt[a[i]];
	while(cnt[mex])	++mex;
	res = mex;
	
	forn(i,1,n - m)
	{
		--cnt[a[i]];
		++cnt[a[i + m]];
		if(cnt[a[i]] == 0 && mex > a[i])	mex = a[i];
		else	while(cnt[mex])	++mex;
		res = min(res,mex);
	}
	printf("%d\n",res);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM