其实这个题看明白了挺简单的。
题目大意: 给你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;
}