导航

POJ 3270 【组合数学】

Posted on 2016-03-19 19:52  tun~  阅读(175)  评论(0编辑  收藏  举报

题意:

给长度为N的学列,然后让你通过置换来使其递增。原序列没有相同的数字。

1 ≤ N ≤ 10,000

ai<=100000

思路:

先找到循环,然后根据贪心只有两种比较好的情况,让循环里边最小的数作为循环的起点,或者在循环外边找到最小的数作为置换的起点。

坑点:

wa三次的原因是循环外的那个公式写错...因为最后还是要多换一次的...

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
long long jilu[10050];
long long xu[10050];
long long sum[10050];
long long mmin[10050];
long long num[10050];
bool vis[10050];
bool rel[10050];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%I64d",jilu+i);
        xu[i]=jilu[i];
    }
    sort(xu,xu+n);
    for(int i=0;i<n;i++){
        if(!vis[i]){
            rel[i]=1;
            sum[i]=mmin[i]=jilu[i];
            num[i]=1;
            int tt=i;
            while(upper_bound(xu,xu+n,jilu[tt])-xu-1!=i){
                tt=upper_bound(xu,xu+n,jilu[tt])-xu-1;
                vis[tt]=1;
                sum[i]+=jilu[tt];
                mmin[i]=min(mmin[i],jilu[tt]);
                num[i]++;
            }
        }
    }
    long long ans=0;
    for(int i=0;i<n;i++){
        if(rel[i]){
            ans+=min((num[i]-1)*mmin[i]+sum[i]-mmin[i],xu[0]*num[i]+sum[i]+xu[0]+mmin[i]);
        }
    }
    printf("%I64d\n",ans);
}