emmm
想写一下逆序对
用了两种方法
归并排序和树状数组
我们看到这道题正常的思路就是暴力(也有可能仅限于本蒟蒻这么想
然后写出了这样的代码
#include<cstdio> using namespace std; int a[500010]; int main() { int n,ans = 0; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } for(int i = 1; i <= n; i++) for(int j = i + 1; j <= n; j++) if(a[j] < a[i]) ans++; printf("%d",ans); return 0; }
emmm
十分简洁的t了十五个点拿了25分
(其实暴力就够了嘛。
但是仔细想逆序对其实就是排序的过程,暴力的思路就是冒泡,显然超时
那么还有一种排序叫做归并
复杂度。。。(我不知道请您自己百度orz
emmmm
归并排序的思路大概都懂吧。
上代码
#include<cstdio> #include<algorithm> using namespace std; #define maxn 500010 #define ll long long ll a[maxn],n; ll qwq[maxn]; ll ans; void qsort(ll l,ll r){ if(l == r) return ; ll mid = (l + r) >> 1; qsort(l,mid); qsort(mid + 1,r); ll i = l,j = mid + 1,k = l; while(i <= mid && j <= r){//合并操作 if(a[i] <= a[j]) qwq[k++] = a[i++]; else qwq[k++] = a[j++],ans += mid - i + 1; } while(i <= mid) qwq[k] = a[i],k++,i++; while(j <= r) qwq[k] = a[j],k++,j++; for(ll i = l;i <= r;i++) a[i] = qwq[i]; }//其实归并排序不是很难emmmm多想一想就好啦 int main(){ scanf("%lld",&n); for(ll i = 1;i <= n;i++) scanf("%lld",&a[i]); qsort(1,n); printf("%lld",ans); return 0; }
再然后呢
学长给我讲了树状数组求逆序对
(这里我们再来膜一下 tql!!!%%%
emmmm
大概就是
利用桶排序的思路,从后往前将数放入数组里
在每一次的数组处加一,并求出其之前的前缀和
最后将前缀和加和,就是答案啦
手推一下就会了~
(当然前置知识树状数组不用我说吧。。。
(然后我正在和离散化过程中两个数相同的情况作斗争,目前写的只有40分
啊对
离散化
就是如果有三个数
30000000 40000000 10000000
太大了
这时候我们可以把这三个数简化成
2 3 1
emmmm
大概这就叫离散化吧
嗯
先放一下40分代码
#include<cstdio> #include<algorithm> using namespace std; #define maxn 500010 #define ll long long ll ans,n; ll www[maxn]; struct Tree{ ll num,QAQ,qwq; }tree[maxn]; bool cmp(Tree x,Tree y){ return x.QAQ < y.QAQ; } bool ccmp(Tree x,Tree y){ return x.qwq < y.qwq; } ll lowbit(ll x){ return x & (-x); } void add(ll x){ while(x <= n){ www[x] ++; x += lowbit(x); } } ll sum(ll x){ ll orz = 0; while(x > 0){ orz += www[x]; x -= lowbit(x); } return orz; } int main(){ scanf("%lld",&n); for(ll i = 1;i <= n;i++){ scanf("%lld",&tree[i].QAQ); tree[i].qwq = i; } sort(tree + 1,tree + n + 1,cmp); for(ll i = 1;i <= n;i++) tree[i].num = i; sort(tree + 1,tree + n + 1,ccmp); for(ll i = n;i >= 1;i--){ add(tree[i].num); ans += sum(tree[i].num - 1); } printf("%lld",ans); return 0; }
等我什么时候用树状数组拿了100
再来写详细注释orz
【溜
-------------------------------------------------------第二天的分割线------------------------------------------------------------------
emmmm
写出来了诶
然而还是不想写注释
#include<cstdio> #include<algorithm> using namespace std; #define maxn 500010 #define ll long long ll ans,n; ll www[maxn]; struct Tree { ll num,QAQ,qwq; } tree[maxn]; bool cmp(Tree x,Tree y) { return x.QAQ < y.QAQ; } bool ccmp(Tree x,Tree y) { return x.qwq < y.qwq; } ll lowbit(ll x) { return x & (-x); } void add(ll x) { while(x <= n) { www[x] ++; x += lowbit(x); } } ll sum(ll x) { ll orz = 0; while(x > 0) { orz += www[x]; x -= lowbit(x); } return orz; }//以上,树状数组操作 int main() { scanf("%lld",&n); for(ll i = 1; i <= n; i++) { scanf("%lld",&tree[i].QAQ);//QAQ记录原始数据 tree[i].qwq = i;//qwq记录输入顺序 } sort(tree + 1,tree + n + 1,cmp);//排QAQ来进行我那被学长称为独特的离散化操作 // for(ll i = 1;i <= n;i++) // tree[i].num = i; int now = 1; int last = tree[1].QAQ; tree[1].num = 1; for(int i = 1; i <= n; i++) { if(tree[i] .QAQ == last) { tree[i].num = now; continue; } last = tree[i].QAQ; now++; tree[i].num = now; }//这里就是我从40到100的转折点emmmm防止数据重复 sort(tree + 1,tree + n + 1,ccmp);//排序qwq使恢复正常输入顺序 for(ll i = n; i >= 1; i--) { add(tree[i].num); ans += sum(tree[i].num - 1); }//从后往前依次放到树状数组里然后求和 printf("%lld",ans); return 0; }
emmmm
写出来了开心~
-----------------------------------------再次分割线----------------------------------------------------
突然想起来把两种代码运行结果放一起比较一下
首先这是归并排序的emmmm
然后是树状数组的
(emmmmm没有对比就没有伤害啊