LZU 第四届校赛
链接:http://oj.lovelyanqi.com/contest/3
H:
首先翻译一下权值,意思就是将原来排列中的 \(i\) 换成了权值排名为第 \(i\) 个的数,
我们发现,只需要20位的排列就可以占满 \(10^18\) 个排名了,所以只需要先把排列前面所有的位置答案算好,
然后暴力统计排列的后 \(20\) 位即可
如果不满 \(20\) 位就更可以暴力了
时间复杂度 \(O(20*m)\)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 100010;
int n, m;
ll ans = 0, b[maxn], fac[30], p[maxn];
struct Num{
int id, a;
bool operator < (const Num &x) const{
return a < x.a;
}
}a[maxn];
int v[30], c[30];
ll calc(ll sum){
for(int i = 1 ; i <= 20 ; ++i) v[i] = 1;
ll tmp = sum;
for(int i = 1 ; i <= 20 ; ++i){
int t = tmp / fac[20 - i];
int cnt = 0;
for(int j = 1 ; j <= 20 ; ++j){
if(v[j]){
if(cnt == t){
c[i] = j;
v[j] = 0;
break;
}
++cnt;
}
}
tmp %= fac[20 - i];
}
// for(int i = 1 ; i <= 19 ; ++i) printf("%d ", c[i]); printf("\n");
if(n < 20){
int d = 20 - n;
for(int i = 1 ; i <= n ; ++i){
p[i] = a[c[i + d] - d].id;
}
} else{
int d = n - 20;
for(int i = n - 19 ; i <= n ; ++i){
p[i] = a[c[20 - (n - i)] + d].id;
}
}
// for(int i = 1 ; i <= n ; ++i) printf("%d ", p[i]); printf("\n");
ll res = 0;
if(n < 20) {
for(int i = 1 ; i <= n ; ++i){
ll f = (i & 1) ? 1ll : -1ll;
res += f * p[i];
}
} else{
for(int i = n - 19 ; i <= n ; ++i){
ll f = (i & 1) ? 1ll : -1ll;
res += f * p[i];
}
}
return res;
}
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
fac[0] = 1; ll sum = 0;
for(int i = 1 ; i <= 20 ; ++i) fac[i] = fac[i - 1] * i;
// for(int i = 1 ; i <= 20 ; ++i) printf("%lld ", fac[i]); printf("\n");
n = read();
for(int i = 1 ; i <= n ; ++i) a[i].a = read(), a[i].id = i;
sort(a + 1, a + 1 + n);
for(int i = 1 ; i <= n ; ++i) p[i] = a[i].id;
if(n >= 20){
for(int i = 1 ; i <= n - 20 ; ++i){
ll f = (i & 1) ? 1ll : -1ll;
sum += f * p[i];
}
}
// for(int i = 1 ; i <= n ; ++i) printf("%d ", a[i].id); printf("\n");
m = read();
for(int i = 1 ; i <= m ; ++i) b[i] = read();
if(n < 20){
ans = 0;
} else{
ans = sum * m;
}
for(int i = 1 ; i <= m ; ++i){
--b[i];
ans += calc(b[i]);
}
printf("%lld\n", ans);
return 0;
}