• [bzoj2058][Usaco2010 Nov]Cow Photographs_树状数组_动态规划


    Cow Photographs bzoj-2058 Usaco-2010 Nov

    题目大意:给定一个n的排列。每次操作可以交换相邻两个数。问将序列变成一个:$i,i+1,i+2,...,n,1,2,...,i-1$形式的序列最少操作次数。

    注释:$1le nle 10^5$。


    想法

    我们做过将序列变成1~n的形式,就是用树状数组求一下逆序对个数。

    而这个题我们先求出i=1的答案,没错就是逆序对个数。

    然后我们考虑如何从$i$变成$i+1$。

    每次,我们考虑将当前序列中最小的数变成最大的数加1,再次求这个序列的逆序对个数,就是i+1的答案。

    他们之间的关系,就是最小的数后面的数的个数减去前面的数的个数。

    理由

    我们设f[i]为i开头的答案。

    假设我们已经知道了f[i]的答案,即当前序列中的数是$i,i+1,i+2,..,n+i-1$。

    这时我们将$i$变成$n+i$,$dic[i]$为i的位置。显然,dic[i]+1到n的数都比n+i小,而1到dic[i]-1的数都比i大,证毕。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010 
    using namespace std; typedef long long ll;
    ll a[N],dic[N]; ll tree[N<<1]; ll n;
    inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
    ll rd() {ll x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
    inline ll lowbit(ll x) {return x&(-x);}
    void update(ll x) {for(ll i=x;i;i-=lowbit(i)) tree[i]++;}
    ll query(ll x) {ll ans=0; for(ll i=x;i<=n+1;i+=lowbit(i)) ans+=tree[i]; return ans;}
    int main()
    {
    	ll now=0,ans=0;
    	n=rd(); for(int i=1;i<=n;i++) a[i]=rd(); for(ll i=1;i<=n;i++)
    	{
    		dic[a[i]]=i; now+=query(a[i]+1);
    		update(a[i]);
    	}
    	ans=now;
    	for(int i=1;i<n;i++)
    	{
    		now+=n+1-2*dic[i];
    		ans=min(ans,now);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    小结:好题好题!!

  • 相关阅读:
    安装selenium
    android MediaPlayer API 详解
    如鹏网学习笔记(六)ADO.Net基础
    如鹏网学习笔记(五)MySql基础
    如鹏网学习笔记(七)HTML基础
    10.12作业
    10.10作业
    201671010111 201620172 《java程序设计》 学习态度的重要性
    201671010111 201620172《面向对象的程序设计》 编程总结
    201671010111 201620172《Java程序设计》再看java
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9716127.html
Copyright © 2020-2023  润新知