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\) 三個數,所以情況數非常少:
- 把一個數變成 \(abc\) 的最小公倍數的倍數
- 把兩個數分別變成一個數的倍數、另外兩個數的最小公倍數的倍數
- 把三個數分別變成三個數的倍數
對於第 \(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都點不上吧,燃起來了。