• [NOIP2013]火柴排队(逆序对)


    题目

    思路

    逆序对只会猜结论

    显然需要先猜个结论:(a)数列第(i)大对应(b)数列第(i)大时平方和有最小值

    通过交换法,需证明:((b_i-a_j)^2+(b_j-a_i)^2 > (b_i-a_i)^2+(b_j-a_j),(j<i))

    上式化简得:(a_j<a_i),显然成立

    (pa_i)表示(i)这个数在(a)数列的哪个位置,(pb_i)同理

    设数列(b_{pa_i}=pb_i),由于需要位置对齐,需要(b_{pa_i}=pa_i),即(b_i=i)

    问题变成求b序列经过多少次交换变成有序序列

    显然逆序对

    Code

    #include<bits/stdc++.h>
    #define N 200005
    #define lowbit(x) ((x)&(-(x)))
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    const ll mod = 99999997; 
    int n,b[N],c[N];
    struct Node
    {
    	int a,loc;
    }A[N],B[N];
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    bool cmp(Node a,Node b) { return a.a<b.a; }
    void update(int x,int v) { for(;x<N;x+=lowbit(x)) c[x]+=v; }
    int query(int x) { int ret=0; for(;x;x-=lowbit(x)) ret+=c[x]; return ret; } 
    int main()
    {
    	read(n);
    	for(int i=1;i<=n;++i) read(A[i].a),A[i].loc=i;
    	for(int i=1;i<=n;++i) read(B[i].a),B[i].loc=i;
    	sort(A+1,A+n+1,cmp);
    	sort(B+1,B+n+1,cmp);
    	for(int i=1;i<=n;++i) b[A[i].loc]=B[i].loc;
    	ll ans=0;
    	for(int i=n;i>=1;--i)
    	{
    		ans=(ans+query(b[i]-1))%mod;
    		update(b[i],1);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    ora-01034 ora-27101解决方法(亲测)
    windows C++内存检测
    oracle求特定字符的个数
    ORACLE查看并修改最大连接数
    你必须用角色管理工具安装Microsoft .NET Framework 3.5
    让VC编译的Release版本程序在其他机器上顺利运行
    创建数据库连接
    C++ 判断进程是否存在
    excel
    毕设学习笔记
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11779211.html
Copyright © 2020-2023  润新知