Description
下面是一段实现冒泡排序算法的C++代码:
for (int i=1;i<n;i++)
for (int j=1;j<=n-i;j++)
if (a[j]>a[j+1])
swap(a[j],a[j+1]);
其中待排序的a数组是一个1~n的排列,swap函数将交换数组中对应位置的值。
对于给定的数组a以及给定的非负整数k,使用这段代码执行了正好k次swap操作之后数组a中元素的值会是什么样的呢?
Input
输入文件共2行。
第1行包含空格隔开的一个正整数n和一个非负整数k;
第2行包含n个空格隔开的互不相同的正整数,表示初始时a数组中的排列。
Output
输出文件共1行。
若在执行完整个代码之后执行swap的次数仍不够k,那么输出一个字符串”Impossible!”(不含引号),否则按顺序输出执行swap操作k次之后数组a的每一个元素,用空格隔开。
Sample Input
1 1
1
1
Sample Output
Impossible!
HINT
n<=10^6
k<=10^12
据说是清华集训的题。。?【雾】
我们用upper[i]记录给定数组中i前面比i大的数的个数。然后二分外层循环做了几次。若做了x次。则总次数=sigma(min(upper[i],x))
然后我们发现,upper[i]<=x的话,那这个数一定排序完毕了。而对于upper[i]>x的部分,他们相对于原数列的位置不变。这样就可以求出做了x次外层循环后的结果了。
然后我们再模拟剩下的一次内层循环就可以了。
【果然我还是太弱。。。感谢ydc大大OTL】
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000001],upper[1000001];
int ans[1000001],sa[1000001];
int tr[1000001];
int n;
inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int x,int xx)
{
int i;
for(i=x;i<=n;i+=lowbit(i))
tr[i]+=xx;
}
inline int sum(int x)
{
int ans=0;
int i;
for(i=x;i>=1;i-=lowbit(i))
ans+=tr[i];
return ans;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
long long k;
scanf("%d%lld",&n,&k);
int i;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
int s=0;
for(i=1;i<=n;i++)
{
upper[i]=sum(n)-sum(a[i]);
add(a[i],1);
}
int l=1,r=n;
long long sx;
while(l<=r)
{
int mid=(l+r)/2;
sx=0;
for(i=1;i<=n;i++)
sx+=(long long)min(mid,upper[i]);
if(sx<=k)
l=mid+1;
else
r=mid-1;
}
sx=0;
for(i=1;i<=n;i++)
sx+=(long long)min(r+1,upper[i]);
long long m=k-sx;
if(m>0)
{
printf("Impossible!\n");
return 0;
}
sx=0;
for(i=1;i<=n;i++)
sx+=min(r,upper[i]);
m=k-sx;
int p=0;
for(i=1;i<=n;i++)
{
if(upper[i]>r)
ans[i-r]=a[i];
else
{
p++;
sa[p]=a[i];
}
}
sort(sa+1,sa+1+p);
p=0;
for(i=1;i<=n;i++)
{
if(ans[i]==0)
{
p++;
ans[i]=sa[p];
}
}
for(i=1;i<n&&m!=0;i++)
{
if(ans[i]>ans[i+1])
{
int t=ans[i];
ans[i]=ans[i+1];
ans[i+1]=t;
m--;
}
}
for(i=1;i<=n-1;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[i]);
return 0;
}