AtCoder Beginner Contest 369 - VP記錄

Jerrycyx發表於2024-10-21

A - 369

樣例已經包括了所有的情況(真良心)

點選檢視程式碼
#include<cstdio>
#include<algorithm>
using namespace std;

int main()
{
	int a,b; scanf("%d%d",&a,&b);
	int ans=0;
	if(a>b) swap(a,b);
	if(a==b) ans=1;
	else if((b-a)&1) ans=2;
	else ans=3;
	printf("%d\n",ans);
	return 0;
}

B - Piano 3

最開始左右手分別放在最初需要用左右手的鍵上,然後模擬即可。

點選檢視程式碼
#include<cstdio>
#include<cmath>
using namespace std;

int main()
{
	int n; scanf("%d",&n);
	int l=0,r=0,ans=0;
	for(int i=1;i<=n;i++)
	{
		int x; char s[5];
		scanf("%d%s",&x,s);
		if(s[0]=='L')
		{
			if(!l) l=x;
			ans+=abs(l-x);
			l=x;
		}
		if(s[0]=='R')
		{
			if(!r) r=x;
			ans+=abs(r-x);
			r=x;
		}
	}
	printf("%d\n",ans);
	return 0;
}

C - Count Arithmetic Subarrays

簡單題。

有一個性質(我沒有證明,但看上去就是對的):等差數列的子串一定是等差數列。

所以雙指標找出原數列的所有的極大等差數列子串(即這個等差數列不是任何更大等差數列的真子串),然後這個等差數列的內每一個區間都是等差數列,公式求數量即可。

還要注意兩個相鄰的等差數列在邊界上會公用一個元素,這個元素所構成的單元素等差數列不能重複計算,要減一。但是最後答案要加一個來補齊數列的兩端。

#include<cstdio>
using namespace std;

const int N=2e5+5;
int n,a[N];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	int l=0,r=0;
	long long ans=0;
	for(l=1;l<n;l=r)
	{
		for(r=l+1;r<=n;r++)
			if(a[r+1]-a[r]!=a[r]-a[r-1]) break;
		int len=r-l+1;
		ans+=1ll*(1+len)*len/2-1;
	}
	printf("%lld\n",ans+1);
	return 0;
}

D - Bonus EXP

一眼 DP。

\(f_{0,i}\) 表示前 \(i\) 個數中,已經選了偶數個小怪的最大經驗值;\(f_{1,i}\) 則表示選了奇數個的。

那麼當前的每隻小怪就有選和不選兩種選擇。

如果不選,\(f_{k,i} = f_{k,i-1}\),不變。

如果選了第 \(i\) 只小怪,那麼小怪數量的奇偶性轉換,

\[f_{k,i} = \left \{ \begin{aligned} &f_{1,i-1} + 2 a_i &, k=0 \\ &f_{0,i-1} + a_i &, k=1 \end{aligned}\right.\]

最後答案即為 \(\max\{f_{0,n},f_{1,n}\}\)

E - Sightseeing Tour

因為 \(n \le 400\),所以 Floyd 跑出全源最短路。

因為 \(k \le 5\),所以直接列舉所有可能的走法(五條邊走的順序和每條邊進入的位置),然後依次用剛才求出的全源最短路累加求出按照這個走法從 \(1\) 走到 \(n\) 的最短路。

最後所有走法的最短路的最小值即為所求。

時間複雜度 \(O( n^3 + q \times k! \times 2^k )\)

程式碼稍微有點難度,不過可以用 C++ 的一些函式減輕工作量。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=405,M=2e5+5,K=10;
int n,m,raw_g[N][N];
pair<pair<int,int>,int> raw_edge[M];
long long g[N][N];
int q,k,b[K],od[K<<1];

void Floyd()
{
	for(int i=1;i<=n;i++)
		g[i][i]=0;
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
	return;
}

int main()
{
	scanf("%d%d",&n,&m);
	memset(g,0x3f,sizeof(g));
	for(int i=1;i<=m;i++)
	{
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		raw_edge[i]={{x,y},z};
		raw_g[x][y]=g[x][y]=min(g[x][y],(long long)z);
		raw_g[y][x]=g[y][x]=min(g[y][x],(long long)z);
	}
	Floyd();
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d",&k);
		for(int j=1;j<=k;j++)
			scanf("%d",&b[j]);
		sort(b+1,b+k+1);
		long long ans=1e18;
		do
		{
			for(int z=0;z<1<<k;z++)
			{
				long long len=0;
				for(int j=1;j<=k;j++)
				{
					od[j*2-1]=raw_edge[b[j]].first.first;
					od[j*2]=raw_edge[b[j]].first.second;
					if((z>>j-1)&1) swap(od[j*2-1],od[j*2]); //reversed
				} //od[1~2k]
				len+=g[1][od[1]];
				for(int j=1;j<=k*2;j+=2)
				{
					len+=raw_edge[b[j+1>>1]].second;
					if(j+2<=k<<1) len+=g[od[j+1]][od[j+2]];
				}
				len+=g[od[k*2]][n];
				ans=min(ans,len);
			}
			next_permutation(b+1,b+k+1);
		}while(!is_sorted(b+1,b+k+1));
		printf("%lld\n",ans);
	}
	return 0;
}

F - Gather Coins

還沒做,等做了再補上。

相關文章