NOIP 模擬 7 壽司
阿新 • • 發佈:2021-06-11
題解
這道題考試的時候直接打暴力,結果暴力連樣例都過不了,最後放上去一個玄學東西,騙了 \(5pts\)。
正解:
此題中我們可以看到原序列是一個環,所以我們要把它拆成一條鏈,那麼我們需要暴力列舉每個點作為斷點,這裡沒有什麼好的優化,因為沒什麼特殊性質
對於每個字元,其對答案的貢獻為 \(\sum_i^n\min(l_i,r_i)\) ,其中 \(l_i\) 和 \(r_i\) 為點 \(i\) 向左或向右移動到邊界的步數,通過手模我們可以發現這就是點 \(i\) 到最左或最右經過的另一種顏色的個數
所以此時我們能容忍的複雜度上只能再加一個 \(\mathcal O(log)\) 或者 \(\mathcal O(1)\)
所以我們考慮維護一個單調指標,對於斷點順時針移動,我們設一個分界點,分界點左側的向左移動到做邊界,右邊的同理,那麼我們可以發現,最有分解點就是沒有一個最有交換經過它,因此這個分解點也是單調順時針移動的。
複雜度分析,對於一個環,我們把它不成一條鏈,那麼它的長度為 \(2n-1\) 而指標單調移動不會出這個範圍,所以此複雜度為 \(\mathcal O(n)\)
目前為止,本篇題解是時間最有的一篇,空間也最小,\(1.3s\)
\(AC\kern 0.4emCODE:\)
Code
#include<bits/stdc++.h> #define ri register int #define p(i) ++i using namespace std; namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++ inline int read() { ri x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } } using IO::read; namespace nanfeng{ #define int long long #define cmax(x,y) ((x)>(y)?(x):(y)) #define cmin(x,y) ((x)>(y)?(y):(x))//常數優化 #define FI FILE *IN #define FO FILE *OUT static const int N=2e6+7; int l[N],bac[N],T,ans,tl; char col[N]; inline int main() { // FI=freopen("nanfeng.in","r",stdin); // FO=freopen("nanfeng.out","w",stdout); T=read(); for (ri z(1);z<=T;p(z)) { scanf("%s",col+1);//讀入優化 int B=0,R=0,lc=0,cnt=0,mv=0,la=0,tp=0,num=0,tot,tt,tmp=0; int len=strlen(col+1); for (ri i(1);i<=len;p(i)) {if (col[i]=='B') p(B);else p(R);} char pc=B<R?'B':'R';//移動數量少的顏色,卡常 tt=cmin(B,R);tot=B+R-tt; for (ri i(1);i<=len;p(i)) { if (col[i]==pc) l[p(tp)]=cnt,bac[i]=tp; else p(cnt); } num=tp;tl=1; while(l[tl]<tot-l[tl]) tmp+=l[tl],p(tl),p(la); for (ri i(tl);i<=tt;p(i)) tmp+=tot-l[i]; ans=tmp; if (col[1]!=pc) p(mv),tmp+=(tt-la)-la; else --la,l[tp+1]=l[1]+tot,p(num); for (ri i(2);i<=len;p(i)) { int k; while((k=(l[tl]-mv))<tot-k&&tl<=num) tmp+=k-(tot-k),p(tl),p(la); ans=cmin(ans,tmp); if (col[i]==pc) {--la;l[tp+bac[i]]=l[bac[i]]+tot;p(num);continue;}//記得在換點時建立新的點資料 else p(mv),tmp+=(tt-la)-la; } printf("%lld\n",ans); } return 0; } #undef int } int main() {return nanfeng::main();}