AtCoder Regular Contest 166 AB題題解

A - Replace C or Swap AB

個人感覺挺有意思的一道思維題(好久沒做思維題了,竟然卡了一個小時)

除去C不看,我們發現X序列中的A只能向後移動,B只能向前移動,且可以移動任意次數。

所以假如沒有C的話,做法是這樣的:

從前往後分別統計X和Y序列中的A的數目,若某一時刻發現X中A的數量小於Y了,那麼就直接No,因爲A只能向後移動

同理,從後往前統計判斷B的數量也是等價的。

現在加上C,考慮這兩種情況:

  • 若Y中某一位是C,而X中該位置不是C:直接No,因爲不存在一個操作讓X的某一位變成C。
  • 若X和Y中的某一位都是C:則該位置可以理解爲一個斷點,該位置左右兩部分的判斷互不干涉。(在代碼中會看到每一部分都分別去判斷)
  • 若X中的一位是C,而Y中該位置不爲C:那麼C肯定要變成A或者B,根據沒有C時候的結論(A只能向後移動,B只能向前移動),最優策略即爲將靠前的C變成A,靠後的變成B即可。

具體操作起來可以不去真的變,直接把C全部變成A/B,然後分別從前/後統計判斷A/B數量即可

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<unordered_set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
string a,b;
bool check(int l,int r){
	if(r<l) return 1;
	int cnta=0,cntb=0;
	for(int i=r;i>=l;i--){
		if(a[i]=='B'||a[i]=='C') cnta++;
		if(b[i]=='B') cntb++;
		if(cnta<cntb) return 0;
	}
	cnta=0,cntb=0;
	for(int i=l;i<=r;i++){
		if(a[i]=='A'||a[i]=='C') cnta++;
		if(b[i]=='A') cntb++;
		if(cnta<cntb) return 0;
	}
	return 1;
}
int main()
{
    ios::sync_with_stdio(false);
	int T;
	cin>>T;
	while(T--){
		int ok=1,n,lst=0;
		cin>>n>>a>>b;
		for(int i=0;i<n;i++){
			if(b[i]=='C'){
				if(a[i]!='C'){
					ok=0;
					break;
				}else{
					if(!check(lst,i-1)){
						ok=0;
						break;
					}else{
						lst=i+1;
					}
				}
			}
		}
		if(!check(lst,n-1))  ok=0;
		if(ok) cout<<"Yes\n";
		else cout<<"No\n";
	} 

    return 0;
}

B - Make Multiples

我們觀察到只有 \(abc\) 三個數,所以情況數非常少:

  1. 把一個數變成 \(abc\) 的最小公倍數的倍數
  2. 把兩個數分別變成一個數的倍數、另外兩個數的最小公倍數的倍數
  3. 把三個數分別變成三個數的倍數

對於第 \(1\) 種情況,把每一個 \(A_i\) 修改的代價算出來,最小值就是答案。

對於第 \(2\) 種情況,把每一個 \(A_i\) 修改的代價分別算出來,答案取各自最小的兩個代價中的一個(因爲有可能兩個最小代價都是修改同一個位置)。

對於第 \(3\) 種情況,同理,計算後排序,答案肯定取各自三個最小代價中的一個。

複雜度 \(O(n)\)

因爲 \(n\) 不是很大,所以我們可以直接省事用 \(sort\) 解決問題 (\(O(nlogn)\) 也可以接受)。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<unordered_set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
const int maxn=200005;
struct node{
	long long va;
	int id;
}m1[maxn],m2[maxn],m3[maxn];
int n;
long long d[maxn];
bool cmp(node a,node b){
	return a.va<b.va;
}
long long gcd(long long a,long long b){
	if(b==0) return a;
	return gcd(b,a%b);
}
long long work1(long long x){
	long long res=1e18+5;
	for(int i=1;i<=n;i++){
		res=min(res,x-((d[i]-1)%x+1));
	}
	return res;
}
long long work2(long long x,long long y){
	for(int i=1;i<=n;i++){
		m1[i].va=x-((d[i]-1)%x+1),m1[i].id=i;
		m2[i].va=y-((d[i]-1)%y+1),m2[i].id=i;
	}
	sort(m1+1,m1+n+1,cmp);
	sort(m2+1,m2+n+1,cmp);
	if(m1[1].id!=m2[1].id) return m1[1].va+m2[1].va;
	return min(m1[1].va+m2[2].va,m1[2].va+m2[1].va);
}
long long work3(long long x,long long y,long long z){
	for(int i=1;i<=n;i++){
		m1[i].va=x-((d[i]-1)%x+1),m1[i].id=i;
		m2[i].va=y-((d[i]-1)%y+1),m2[i].id=i;
		m3[i].va=z-((d[i]-1)%z+1),m3[i].id=i;
	}
	sort(m1+1,m1+n+1,cmp);
	sort(m2+1,m2+n+1,cmp);
	sort(m3+1,m3+n+1,cmp);
	long long res=1e18+5;
	for(int i=1;i<=3;i++){
		for(int j=1;j<=3;j++){
			if(m1[i].id==m2[j].id) continue;
			for(int k=1;k<=3;k++){
				if(m1[i].id==m3[k].id) continue;
				if(m2[j].id==m3[k].id) continue;
				res=min(res,m1[i].va+m2[j].va+m3[k].va);
			}
		}
	}
	return res;
}
int main()
{
    ios::sync_with_stdio(false);
    long long a,b,c;
	cin>>n>>a>>b>>c;
	for(int i=1;i<=n;i++) cin>>d[i];
	long long x1=a/gcd(a,b)*b,x2=b*c/gcd(b,c),x3=a*c/gcd(a,c),x4=x1*c/gcd(x1,c);
	long long ans=work1(x4);
	if(n>2) ans=min(work3(a,b,c),ans);
	if(n>1) ans=min(ans,min(min(work2(x2,a),work2(x3,b)),work2(x1,c)));
	cout<<ans;
    return 0;
}

比賽總結

明顯思維能力下降了,A題竟然卡了一個多小時。以後要多打比賽。

ksun48 在119:57(比賽結束前3秒)的時候交了一發最後一題且A掉了,拿下rank2,估計手速慢了submit都點不上吧,燃起來了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章