1. 程式人生 > >【AtCoder】 AtCoder Beginner Contest 103 (ABC103)

【AtCoder】 AtCoder Beginner Contest 103 (ABC103)

先上一張最終結果的圖吧:

感覺AtCoder的ABC還是比較練手的,考驗程式碼速度,網速,D題還會有一些思維難度。

這次ABC由於網路原因,很遲才看到題,但完成得還是不錯的。

題解:

A

題意:給你三個都需要被完成的任務的難度a,b,c,均為1至100的正整數。

首先,你可以用0的花費完成任何一個任務。

如果你完成了一個任務,那麼你可以完成另一個任務,花費是兩個任務的難度的差的絕對值。

題解:利用絕對值的幾何意義可以發現,最優解一定是選擇難度在中間的那個任務完成,然後再完成另外兩個任務。

那麼最終的花費一定是難度最大的任務的難度減去難度最小的任務的難度。

程式碼:

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

int main()
{
	int a,b,c;
	cin >> a >> b >> c;
	cout << max(max(a,b),c)-min(min(a,b),c) << endl;
}

B

題意:給你字串ST,每次可以對S串進行一種操作:將S串的最後一個字元取出,扔到最前面去。

問是否能將S串變為T串。

S串和T串的長度均小於或等於100且相等。

題解:顯然暴力執行操作,暴力判斷。

程式碼:

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

int main()
{
	string s,t;
	cin >> s >> t;
	for(int i=0;i<s.length();++i)
	{
		char c=s[s.length()-1];
		string tmp=s;
		s.pop_back();
		s.insert(s.begin(),c);
		if(s==t)
		{
			puts("Yes");
			return 0;
		}
	}
	puts("No");
}

C

題意:給你N個正整數a_{1},a_{2},a_{3},...,a_{N},我們定義

f(m)=(m \bmod a_{1})+(m \bmod a_{2})+(m \bmod a_{3})+...+(m \bmod a_{n})

其中m為自然數。

f(m)的最大值。

2 \leq N \leq 30002 \leq a_{i} \leq 10^5

題解:首先這道題求的是最大值(最小值顯然為0),容易想到暴力列舉m,但顯然會超時。

細心的讀者也許發現了,我C題的通過時間比B題早將近7分鐘,原因竟然是:

當我碼著B題,想著C題的時候,隔壁一名大佬(STO yeh)突然說了聲最小公倍數。

我一想,m取所有數的最小公倍數減一,那麼。。。。。

那麼C題比B題好碼多了,於是碼了C,於是C題便比B早提交。。。別問我為什麼還過了7分鐘才交B

證明:這個不需要證明吧。。。。

程式碼:

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

int main()
{
	int n,x,sum=0;
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&x);
		sum+=x-1;
	}
	printf("%d\n",sum);
}

的確比B好碼得多啊。。。。

D

沒錯又是一道有思維難度的題目(大佬除外)。

題意:給你一條n個點的鏈,點按順序標號為1n,然後輸入一些點對,讓你刪邊,使得這些點對都不連通,求最少刪邊數量。

2\leq N \leq 10^51\leq M\leq 10^51\leq ai< bi\leq N

題解:在這道題上卡了很久。

其實不應該卡那麼久,因為曾經做過這道題的樹上版本,但由於那道題是刪點,所以一開始以為不適用,但是後來想了一想,其實可以套用。

方法就是:將所有區間按照右端點的大小排序(從小到大),然後對於一個區間,若它當前未被切斷,則切斷它最右的一條邊。

證明:用類似歸納法的思想,對於右端點最小(最左)的區間,它一定要被切斷,為了“惠及”儘可能多的區間,切斷它最右的一條邊。為什麼最優呢,因為這是它已經是右端點最左的區間了,因此只有切斷最右的那條邊,才能切斷最多的區間。

於是我們排除掉已經被切斷的區間,再次找到右端點最小的未被切斷的區間,由於前面的決策是最優的(已證明),我們可以忽略掉那些區間。此時,切斷該區間最右的邊一定是最優的,證法同上。

拓展:關於樹上的做法(那道題是刪點),將所有點對的lca按照深度排序,從深度大的點往深度小的點刪,證法類似,不詳細展開,有興趣的讀者可以自行查閱資料。

程式碼:

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

#define MAXN 100001

struct data{
	int a,b;
	bool operator<(const data &d)const{
		return b<d.b;
	}
}a[MAXN];

int n,m;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&a[i].a,&a[i].b);
	}
	sort(a+1,a+m+1);
	int now=0,ans=0;
	for(int i=1;i<=m;++i)
	{
		if(now<=a[i].a)
		{
			now=a[i].b;
			++ans;
		}
	}
	printf("%d\n",ans);
}