...其实我知道要用归并排个序找个找到逆序对总数-k就好了,但是我当时以为自己想到了另一个算逆序对的方法,以为这是正确的。。所以才没用归并排序,,后面就一直调,忘了用归并。。。。整个人都不好了
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=52584
以下是归并排序:
最后面是树状数组
+
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; __int64 a[100000+5]; __int64 b[100000+5]; __int64 guibing(__int64 a[],__int64 l,__int64 r) { if (l==r) return 0; __int64 sum=0; __int64 mid=(l+r)/2; sum+=guibing ( a, l,mid); sum+=guibing ( a, mid+1, r); __int64 ok=l; __int64 i,j; for (i=l,j=mid+1;i<=mid&&j<=r;) { if (a[i]>a[j]) //此处一定要大于号,否则归并排序稳定性就没了,如果有等于号 那么5 和 5也会交换,也被计入逆序对中,树状数组同理 { b[ok++]=a[j]; j++; sum+=(mid+1)-i; //对每一个d[j],如果a[i<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">]大于它,那么a[i]到a[mid]的全部元素都大于a[j],都mid-i+1对逆序对</span>
} else { b[ok++]=a[i]; i++; } } while (i<=mid) { b[ok++]=a[i]; i++; } while(j<=r) { b[ok++]=a[j]; j++; } for (i=l;i<=r;i++) a[i]=b[i]; return sum; } int main() { __int64 n,k; while(scanf("%I64d%I64d",&n,&k)!=EOF) { __int64 i; for (i=1;i<=n;i++) { scanf("%I64d",&a[i]); } __int64 ans=guibing(a,1,n); if (k>=ans) printf("0\n"); else printf("%I64d\n",ans-k); } return 0; }
以下是树状数组代码:
</pre><pre name="code" class="cpp" style="font-size: 14.4444446563721px;">//离散化+树状数组 #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; __int64 n,m; struct node { __int64 x; __int64 num; }; node tm[100000+5]; __int64 posi[100000+5]; __int64 tree[100000+5]; inline __int64 lowbit(__int64 x) { return x&-x; } void add(__int64 x,__int64 value) { for (__int64 i=x;i<=n;i=i+lowbit(i)) { tree[i]+=value; } } __int64 get(__int64 x) { __int64 sum=0; for (__int64 i=x;i;i-=lowbit(i)) { sum+=tree[i]; } return sum; } __int64 cmp(node a,node b) { return a.x<b.x; } int main() { // freopen( "1.out","r",stdin ); // scanf 从1.txt输入 // freopen( "test.out","w",stdout ); //pr__int64f输出到1.tx while(scanf("%I64d%I64d",&n,&m)!=EOF) { memset(tree,0,sizeof(tree)); __int64 i; for (i=1;i<=n;i++) { scanf("%I64d",&tm[i].x); tm[i].num=i; } stable_sort(tm+1,tm+1+n,cmp); //一定要稳定排序,sort会在排序中改变了相同大小元素的编号 例如 4 2 5 5 1 对应的离散化后的数为 3 2 4 5 1 如果是不稳定排序 可能会是 3 2 5 4 1 那样 逆序对就多了一对了。。。同样在归并排序中也要注意。 for(i=1;i<=n;i++) { posi[tm[i].num]=i; } __int64 ans=0; for (i=n;i>=1;i--) { ans+=get(posi[i]); add(posi[i],1); } if (m>=ans) printf("0\n"); else printf("%I64d\n",ans-m); } return 0; }
//离散化+树状数组 #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; __int64 n,m; struct node { __int64 x; __int64 num; }; node tm[100000+5]; __int64 posi[100000+5]; __int64 tree[100000+5]; inline __int64 lowbit(__int64 x) { return x&-x; } void add(__int64 x,__int64 value) { for (__int64 i=x;i<=n;i=i+lowbit(i)) { tree[i]+=value; } } __int64 get(__int64 x) { __int64 sum=0; for (__int64 i=x;i;i-=lowbit(i)) { sum+=tree[i]; } return sum; } __int64 cmp(node a,node b) { return a.x<b.x; } int main() { // freopen( "1.out","r",stdin ); // scanf 从1.txt输入 // freopen( "test.out","w",stdout ); //pr__int64f输出到1.tx while(scanf("%I64d%I64d",&n,&m)!=EOF) { memset(tree,0,sizeof(tree)); __int64 i; for (i=1;i<=n;i++) { scanf("%I64d",&tm[i].x); tm[i].num=i; } stable_sort(tm+1,tm+1+n,cmp); for(i=1;i<=n;i++) { posi[tm[i].num]=i; } __int64 ans=0; for (i=n;i>=1;i--) { ans+=get(posi[i]); add(posi[i],1); } if (m>=ans) printf("0\n"); else printf("%I64d\n",ans-m); } return 0; }