gym 102028 C The Problem Needs 3D Arrays

题意:

给定n个互不相同的数,从中选取一个子序列使得子序列中逆序对的个数/子序列长度最大。

题解:

由于n的范围为100,可以往网络流方向思考,发现若将逆序对都连边,问题所求就变成图中子图边数/子图点数的最大值。
而这类问题便可以想到最大密度子图问题, a n s = ∑ E ′ ∈ E 1 ⋅ X e ∑ V ′ ∈ V 1 ⋅ X v ans=\frac{ \sum_{E' \in E}{1 \cdot X_e} }{\sum_{V' \in V}{1 \cdot X_v}} ans=VV1XvEE1Xe 将该式子化简就可以得到 ∑ E ′ ∈ E 1 ⋅ X e − a n s ⋅ ∑ V ′ ∈ V 1 ⋅ X v \sum_{E' \in E}{1 \cdot X_e} -ans \cdot \sum_{V' \in V}{1 \cdot X_v} EE1XeansVV1Xv 显然这个函数是单调的,所以可以二分ans,之后就可以发现是一个最大闭合子图问题,转化为最小割去解即可。

代码:

/**
 *     author:     TelmaZzzz
 *     create:     2019-09-21-15.04.29
**/
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
//#include <random>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
void _R(int &x) { scanf("%d", &x); }
void _R(ll &x) { scanf("%lld", &x); }
void _R(db &x) { scanf("%lf", &x); }
void _R(char &x) { scanf(" %c", &x); }
void _R(char *x) { scanf("%s", x); }
void R() {}
template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); }
void _W(const int &x) { printf("%d", x); }
void _W(const ll &x) { printf("%lld", x); }
void _W(const db &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
template<class T> void _W(const vector<T> &x) { for (auto i = x.begin(); i != x.end(); _W(*i++)) if (i != x.cbegin()) putchar(' '); }
void W() {}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define erp(x,y,z) for(int x=y;x>=z;x--)
#define PB push_back
#define MP make_pair
#define INF 100000000
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
//mt19937 rand_(time(0));
const int N=10200,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//逆元
db wei[M];
int head[N],NEXT[M],ver[M],tot;void link(int u,int v,db w){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;wei[tot]=w;}
void TelmaZzzz(){
#ifndef ONLINE_JUDGE
    freopen("1.txt","r",stdin);
#endif
}
namespace fastIO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
const db EPS=1e-7;
inline int sign(db a){return a<-EPS?-1:a>EPS;}
inline int cmp(db a,db b){return sign(a-b);}
vector<pair<int,int> >mp;
int n;
int S,T;
int d[10200];
int a[N];
queue<int>q;
db Min(db x,db y){
    if(cmp(x,y)<=0) return x;
    return y;
}
bool bfs(){
    rep(i,1,T) d[i]=0;
    while(q.size()) q.pop();
    q.push(S);
    d[S]=1;
    while(q.size()){
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=NEXT[i]){
            int y=ver[i];
            if(wei[i]>EPS&&!d[y]){
                q.push(y);
                d[y]=d[x]+1;
                if(y==T) return true;
            }
        }
    }
    return false;
}
db dinic(int x,db flow){
    if(x==T) return flow;
    db rest=flow,k;
    for(int i=head[x];i;i=NEXT[i]){
        int y=ver[i];
        if(wei[i]>EPS&&d[y]==d[x]+1){
            k=dinic(y,Min(rest,wei[i]));
            if(k<EPS) d[y]=0;
            wei[i]-=k;
            wei[i^1]+=k;
            rest-=k;
            if(rest<EPS) return flow;
        }
    }
    if(rest<EPS) d[x]=0;
    return flow-rest;
}
db build(db x){
    tot=1;
    S=1,T=2+n+(int)mp.size();
    rep(i,1,T) head[i]=0;
    int index=1;
    db up=0.0;
    rep(i,0,(int)mp.size()-1){
        up+=1.0;
        link(S,index+n+1,1.0);
        link(index+n+1,S,0.0);
        link(index+n+1,mp[i].first+1,INF);
        link(mp[i].first+1,index+n+1,0.0);
        link(index+n+1,mp[i].second+1,INF);
        link(mp[i].second+1,index+n+1,0.0);
        index++;
    }
    rep(i,1,n){
        link(i+1,T,x);
        link(T,i+1,0.0);
    }
    db flow=0.0;
    db maxflow=0.0;
    while(bfs()){
        while(cmp(flow=dinic(S,INF),0.0)>0){
            maxflow+=flow;
        }
    }
    //cout<<x<<' '<<up-maxflow<<' '<<up<<' '<<maxflow<<endl;
    return up-maxflow;
}
int main(){
    TelmaZzzz();
    //ios::sync_with_stdio(false);
    int t;
    read(t);
    int ti=0;
    while(t--){
        read(n);
        vector<pair<int,int> >mp_;
        swap(mp_,mp);
        rep(i,1,n){
            read(a[i]);
        }
        rep(i,1,n){
            rep(j,i+1,n){
                if(a[i]>a[j]) mp.PB(MP(a[i],a[j]));
            }
        }
        db l=0.0,r=1.0*mp.size();
        //cout<<build(2.8)<<endl;
        while((r-l)>EPS){
            db mi=1.0*(l+r)/2.0;
            if(build(mi)<EPS) r=mi;
            else l=mi;
        }
        //cout<<build(1.25)<<endl;
//        rep(i,1,tot) cout<<wei[i]<<' '<<wei[i^1]<<endl;
//        cout<<endl;
        printf("Case #%d: %.15f\n",++ti,r);
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值