bzoj 3580: 冒泡排序

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

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值