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

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 106 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
#include
#include
#include
#include
#include
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  v[maxn];
queue  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;
}

你可能感兴趣的:(网络流,最小割)