题目链接:
http://codeforces.com/problemset/problem/645/B
题意:
给定步数和排列,每步可以交换两个数,问最后逆序数最多是多少对?
分析:
看例子就能看出来肯定是不断往中间逼近,然后交换头尾两个,给定交换的对数,直接算就好了,复杂度 O(1)
代码:
#include<iostream>
using namespace std;
typedef long long ll;
int main (void)
{
ll n, m;
cin>>n>>m;
ll res = 0;
ll ans = min(n/2, m);
res = (n - 1+ (n - ans + 1))/ 2 * ans + (n - 2 * ans + n - ans - 1)/2 * ans;
cout<<res<<endl;
return 0;
}
智商压制
直接用所有对数减去为改变的对数就好了嘛
#include<iostream>
using namespace std;
int main (void)
{
long long n, m;
cin>>n>>m;
long long res = max(n - 2 * m, 0ll);
long long ans = n * (n - 1)/2 - res * (res - 1) / 2;
cout<<ans<<endl;
return 0;
}
然后求逆序数的经典方法就是树状数组了,这里写下,时间复杂度 O(nlogn)
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 400020;
int bit[maxn], a[maxn];
int n, m;
int sum(int i)
{
int s = 0;
while(i){
s += bit[i];
i -= i & -i;
}
return s;
}
void add(int i, int x)
{
while(i <= n){
bit[i] += x;
i += i & -i;
}
}
int main (void)
{
cin>>n>>m;
if(m >= n / 2){
cout<<(ll) n * (n - 1)/2<<endl;
return 0;
}
for(int i = 1; i <= n; i++) a[i] = i;
for(int i = 1; i <= m; i++) swap(a[i], a[n - i + 1]);
ll res = 0;
for(int i = 1; i <= n; i++){
add(a[i], 1);
res +=i - sum(a[i]);
}
cout<<res<<endl;
}