其實這個題看明白了挺簡單的。
題目大意: 給你n個不流通的硬幣,然後每次替換其中一個,每替換一個就詢問一次按照Dima的算法需要幾次才能最終沒有可以相互交換的coin。
每次替換之後,按照Dima的算法執行時,coin的順序是不變的,因爲題目中說了DIma只可以在心中想,不可以移動coin。
題解:首先要想明白每次執行Dima的算法都會把一個不流通的coin移動到最後面,所以題目就變成了每次替換之後有幾個coin沒有放在最後面的位置。
變量:p:從後往前第一個不流通的coin的位置,即p後面的coin已經都是流通coin了,需要移動的在前面 初始p=n;
ok:已經放在最後面連續的流通coin的個數,也就是ok=n-p; 初始ok=0;
a[i]:第i次要替換的位置
book[i]:第i個位置上是否已經替換
if(a[i]<p) 如果要替換的coin沒放在最後面,那麼移動次數 ans=i-ok+1; 這一次的算法的執行數量就是把前面i-ok個都移動回來就是i-ok次,加一是因爲不移動爲1 然後 boo[a[i]]=1;
if(a[i] == p) 表明這一個放在最後的位置上了,這次移動不用管這個了 book[a[i]]=1;
然後往前看,while(book[p]){p--;ok++;} 找下一個p的值,並且更新ok
p是肯定大於a[i] 因爲p是可以替換的位置的最後面的值。
第一次和最後一次可以不用管,直接輸出1。
AC代碼,就20多行,時間複雜度爲O(N)
#include<iostream>
using namespace std;
const int maxn = 300005;
int a[maxn],book[maxn];
int n,p,ok;
int main()
{
cin>>n;
p=n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
printf("1 ");
for(int i=1;i<n;i++){
if(a[i]<p){
printf("%d ",i-ok+1);
book[a[i]]=1;
}
else if(a[i]==p){
book[a[i]]=1;
while(book[p]){ p--;ok++; }
printf("%d ",i-ok+1);
}
}
printf("1");
return 0;
}