您的位置:首页 > 其它

2014-2015 ACM-ICPC, Asia Xian Regional Contest C

2016-09-07 22:09 423 查看
Problem C. The Problem Needs 3D Arrays

Description

A permutation is a sequence of integers
p1, p2,
. . . , pn, consisting of
n distinct positive

integers and each of them does not exceed
n. Assume that
r(S)
of sequence
S denotes the

number of inversions in sequence
S (if
i < j and
Si > Sj, then the
pair of (i, j)
is called an

inversion of
S),
l(S)
of sequence
S denotes the length of sequence
S. Given a permutation
P

of length
n, it’s your task to find a subsequence
S of
P with maximum
r l( (S S) ).
A subsequence

of P is a sequence (pi1,
pi2, . . . , pit)
which satisfies that 0
< i1
< i2
< . . . < it ≤
n.

Input

The first line of the input gives the number of test cases, T. T test cases follow.

For each test case, the first line contains an integer
n (1
≤ n
≤ 100), the length of

the permutation
P. The second line contains
n integers
p1, p2,
. . . , pn, which represents the

permutation
P.

Output

For each test case, output one line containing “Case #x: y”, where x is the test case

number (starting from 1) and y is the maximum
r l( (S S) ).

Your answer will be considered correct if it is within an absolute error of
10−6
of the correct

answer.

Samples

Sample Input Sample Output

15

3 4 2 5 1

Case
#1: 1.250000000000

题意:

有一个长度为n的序列,现要从中选择一个子序列s,

定义r(s):子序列的逆序对数

l(s):子序列的长度

要求r(s)/l(s)的最大值



solution:

二分ans,判断r(s)/l(s)
>= ans


若不等式成立则答案不小于ans

变形得r(s)
- l(s)*ans >= 0


这个东西意味着我们要舍去一些逆序对,同时减去一个东西

那最优的方案就是让花费的代价最小

联系到最小割,利用最大权闭合子图的方法

源点向每个位置连边,权值为ans

若两点(i,j)构成逆序对,构建一个辅助点k,i->k容量为INF,j->k容量为INF,k->汇点容量为1

判断初始逆序对
- 最大流是否大于零


正确性就不赘述了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;

const int maxn = 1E4 + 1E3 + 10;
const int maxm = 1E5 + 10;
const int INF = ~0U>>1;
typedef double DB;
const DB eps = 1E-12;

struct E{
int to;
DB cap,flow;
E(){}
E(int to,DB cap,DB flow): to(to),cap(cap),flow(flow){}
}edgs[maxm];

int n,m,s,t,cnt,T,tot,Cnt,a[111],L[maxn],vis[maxn],cur[maxn];
DB ori;

vector <int> v[maxn];
queue <int> Q;

void Add(int x,int y,DB cap)
{
v[x].push_back(cnt);
edgs[cnt++] = E(y,cap,0);
v[y].push_back(cnt);
edgs[cnt++] = E(x,0,0);
}

bool BFS()
{
vis[s] = ++Cnt;
L[s] = 1;
Q.push(s);
while (!Q.empty()) {
int k = Q.front(); Q.pop();
for (int i = 0; i < v[k].size(); i++) {
E e = edgs[v[k][i]];
if (e.cap - e.flow <= eps) continue;
if (vis[e.to] == Cnt) continue;
vis[e.to] = Cnt;
L[e.to] = L[k] + 1;
Q.push(e.to);
}
}
return vis[t] == Cnt;
}

DB Dicnic(int x,DB a)
{
if (x == t) return a;
DB flow = 0;
for (int &i = cur[x]; i < v[x].size(); i++) {
E &e = edgs[v[x][i]];
if (e.cap - e.flow <= eps) continue;
if (L[e.to] != L[x] + 1) continue;
DB f = Dicnic(e.to,min(a,e.cap - e.flow));
if (f < eps) continue;
e.flow += f;
edgs[v[x][i]^1].flow -= f;
a -= f;
flow += f;
if (a <= eps) return flow;
}
if (flow <= eps) L[x] = -1;
return flow;
}

bool Judge(DB now)
{
ori = 0;
cnt = 0;
s = 0;
t = tot = n + 1;
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
if (a[i] > a[j]) {
++tot;
Add(i,tot,INF);
Add(j,tot,INF);
Add(tot,t,1);
ori += 1.00;
}
for (int i = 1; i <= n; i++) Add(s,i,now);

DB MaxFlow = 0;
while (BFS()) {
for (int i = 0; i <= tot; i++) cur[i] = 0;
MaxFlow += Dicnic(s,INF);
}
for (int i = 0; i <= tot; i++) v[i].clear();
return ori - MaxFlow >= eps;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif

cin >> T;
for (int I = 1; I <= T; I++) {
scanf("%d",&n);
for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
DB L = 0,R = n + 1;
for (int i = 0; i < 50; i++) {
DB mid = (L + R) / 2.00;
if (Judge(mid)) L = mid;
else R = mid;
}
printf("Case #%d: %.12lf\n",I,L);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: