zoukankan      html  css  js  c++  java
  • [usaco2009nov]奶牛的图片

    Farmer John希望给他的N(1<=N<=100,000)只奶牛拍照片,这样他就可以向他的朋友炫耀他的奶牛.这N只奶牛被标号为1..N.
    在照相的那一天,奶牛们排成了一排.其中第i个位置上是标号为c_i(1<=c_i<=N)的奶牛.对于奶牛的站位,Farmer John有他自己的想法.
    FJ是这么想的,标号为i(1<=i<=n-1)的奶牛只能站在标号为i+1的奶牛的左边,而标号为N的奶牛只能站在标号为1的奶牛的左边.当然,没有牛可以站在队列中最左边的奶牛的左边了.也就是说,最左边的奶牛编号是随意的.
    这些奶牛都非常的饿,急切的希望吃到FJ承诺的在拍照后的大餐,所以FJ想尽快的拍照.奶牛们的方向感非常的不好,所以FJ每一分钟只可以选择相邻的两只奶牛然后让他们交换位置.FJ最小需要多少时间就能使奶牛站成一个可以接受的序列?
    比方说一个有5只奶牛的例子,一开始序列是这样的:
       左边       右边
        3  5  4  2  1

    第一分钟,FJ可以交换第二队奶牛(即5和4),交换后的队列:
        3  4  5  2 1
    第二分钟,FJ交换最右边的一对,序列变成这样:
        3  4  5  1  2
    这样,只用了2分钟,就是序列变为了一个FJ所希望的序列.

    解题过程:刚写这道题时,没有看到题目中的"相邻"两个字,于是当成了置换来做,找使循环节最多的序列,一时间没想到什么办法,敲了个暴力交了一下,发现wa了,重新读题后发现了题目中有"相邻"两个字;

    由于每次相邻的两个数字交换,每次交换一定会使逆序对数减小或增加1,可以证明最小的移动次数是逆序对数,然后就可以O(nlogn),求一个序列的逆序对数;

    但是最左端的数字不确定,考虑一下如果顺序变化序列对逆序对数有什么影响,可以让每个数加1,如果这个数是n,则变成1这样的顺序来变换序列;

    这样很容易看出,其他数字+1对逆序对数没影响,只有n变成1这个变化会对逆序对数造成影响,然后就可以O(n)的复杂度顺序转移;

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<iomanip>
    #include<map>
    #include<set>
    #include<vector>
    #include<ctime>
    #include<cmath>
    #define LL long long 
    using namespace std;
    #define LL long long 
    #define up(i,j,n) for(int i=(j);(i)<=(n);(i)++)
    #define max(x,y) ((x)<(y)?(y):(x))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define FILE "1"
    namespace OI{
        const int maxn=101000;
        int n,a[maxn],b[maxn];
        void init(){
            scanf("%d",&n);
            up(i,1,n)scanf("%d",&a[i]);
            up(i,1,n)b[a[i]]=i;
        }
        bool vis[maxn];
        int c[maxn];
        int lowbit(int x){return x&-x;}
        int sum(int x){int ans=0;while(x>0)ans+=c[x],x-=lowbit(x);return ans;}
        void add(int x){while(x<=n)c[x]+=1,x+=lowbit(x);}
        LL get(){
            LL ans=0;
            up(i,1,n){
                ans+=sum(n-a[i]+1);
                add(n-a[i]+1);
            }
            return ans;
        }
        void work(){
            LL ans=get();
            LL minn=ans;
            for(int i=n;i>=1;i--){
                ans=ans+2*b[i]-n-1;
                minn=min(ans,minn);
            }
            cout<<minn<<endl;
        }
        void slove(){
            init();
            work();
        }
    }
    
    int main(){
        using namespace OI;
        slove();
    }
    View Code
  • 相关阅读:
    mtd
    .NET快速开发框架-RDIFramework.NET 全新EasyUI版发布
    EntityFramework Core 5.0 VS SQLBulkCopy
    动态拼接Lambda表达式-表达式目录树动态构建及修改-----表达式树的访问过程,并转化成sql语句
    动态拼接Lambda表达式-表达式目录树动态构建及修改
    动态拼接Lambda表达式-表达式目录树动态构建 And Or Not True False等表达式树的扩展
    动态拼接Lambda表达式-表达式目录树动态构建=Expression<Func<MyClass, int>> expressionFunc = x => x.Age + 1
    动态拼接Lambda表达式-表达式目录树动态构建=Expression<Func<int, int, int>> predicate1 = (m, n) => m * n + 2
    动态拼接Lambda表达式2
    lambda 表达式拼接
  • 原文地址:https://www.cnblogs.com/chadinblog/p/5936896.html
Copyright © 2011-2022 走看看