题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5592
官方题解
设fi是第i个前缀的逆序对数,pi是第i个位置上的数,则fi−fi−1是i前面比pi大的数的个数.我们考虑倒着做,当我们处理完i后面的数,第i个数就是剩下的数中第fi−fi−1+1大的数,用线段树和树状数组可以轻松地求出当前第k个是1的位置,复杂度O(NlogN).
刚开始用了O(n^2) 的方法,由于数据要求50000,所以超时间
第一次树状数组
正确代码
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<stdlib.h>
#define MS(x,y) memset(x,y,sizeof(x))
using namespace std;
void fre(){freopen("t.txt","r",stdin);}
typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 50005;
int ans[maxn],out[maxn],a[maxn],n;
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int d)
{
while(x<=n)
{
ans[x]+=d; x+= lowbit(x);
}
}
int sum(int x)
{
int res = 0;
while(x>0)
{
res += ans[x]; x -= lowbit(x);
}
return res;
}
int calc(int x)
{
int l = 1,r = n,mid;
while(l <= r)
{
mid = (l+r)>>1;
if(x <= sum(mid)) r = mid - 1;
else l = mid + 1;
}
return l;
}
void solve()
{
int i;
for(i = 1; i <= n; i++) add(i,1);
for(i = n; i > 0; i--)
{
out[i] = calc(i - a[i]);
add(out[i],-1);
}
}
int main()
{
// fre();
int t,i;
scanf("%d",&t);
while(t--)
{
MS(ans,0);
scanf("%d",&n);
for(i = 1; i <= n; i++) scanf("%d",&a[i]);
for(i = n; i >= 1; i--) a[i] = a[i] - a[i-1];
solve();
printf("%d",out[1]);
for(i = 2; i <= n; i++) printf(" %d",out[i]);
puts("");
}
return 0;
}
o(n^2)代码,写起来简单
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<stdlib.h>
#define MS(x,y) memset(x,y,sizeof(x))
using namespace std;
void fre(){freopen("t.txt","r",stdin);}
typedef long long LL;
typedef unsigned long long ULL;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
int a[50005];
int main()
{
// fre();
int i,j,t,n,tem,last;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
last = 0;
a[1] = 1;
for(i = 1; i <= n; i++)
{
scanf("%d",&tem);
int x = tem - last;
for(j = 1; j < i; j++)if(a[j]>=i-x) a[j]++;
a[i] = i - x;
last = tem;
}
printf("%d",a[1]);
for(i = 2; i <= n; i++) printf(" %d",a[i]);puts("");
}
return 0;
}