HDU 1394+codeforce 459 D— —归并排序 简单离散化 线段树 树状数组— —求逆序列。

25 篇文章 0 订阅
24 篇文章 0 订阅

HDU 1394

题意:第一个数可以放到最后一个后面,在随意多少个这样的操作或者不操作的情况下,问逆序列最少有多少个。

模拟一下这个操作,由于这道题只有0~N-1,所以就更加方便了。

对于第一个数A[i],比A[i]小的数一定在后面,所以以A[i]为前的逆序列有A[i](从0开始的),放到后面之后,比A[i]大的有n-1-A[i]个,也就是多出了这么些的序列,总共变化位-A[i]+n-1-A[i]

线段树跑一下一开始的逆序列即可。一开始线段树上都是0,每放进去一个赋值为1,代表出现了这个。(按顺序来的后面的发现比他大的已经出现一定是出现在他之前的因为顺序输入)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

const int maxn = 100100;
const int INF=0x7fffffff;

using namespace std;

int lazy[maxn<<2];
int MAX[maxn<<2];
int MIN[maxn<<2];
int SUM[maxn<<2];

void PushUp(int rt) { //由左孩子、右孩子向上更新父节点
    SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
    MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]);
    MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}

void PushDown(int rt,int m) { //向下更新
    if (lazy[rt]) { //懒惰标记
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        SUM[rt<<1] = (m - (m >> 1)) * lazy[rt];
        SUM[rt<<1|1] = ((m >> 1)) * lazy[rt];
        MAX[rt<<1]=MAX[rt<<1|1]=lazy[rt];
        MIN[rt<<1]=MIN[rt<<1|1]=lazy[rt];
        lazy[rt] = 0;
    }
}

//所有的l,r,rt  带入1,n,1
void build(int l,int r,int rt) { //初始化建树
    lazy[rt] = 0;
    if (l== r) {
        SUM[rt]=MAX[rt]=MIN[rt]=0;  //初始化为0的建树
        /*scanf("%d",&SUM[rt]);  //边读入边建树的方法
          MAX[rt]=MIN[rt]=SUM[rt];
        */
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(rt);
}

void update(int L,int R,int v,int l,int r,int rt) { //将L~R区间的值置为v
    //if(L>l||R>r) return;
    if (L <= l && r <= R) {
        lazy[rt] = v;
        SUM[rt] = v * (r - l + 1);
        MIN[rt] = v;
        MAX[rt] = v;
        //printf("%d %d %d %d %d\n", rt, sum[rt], c, l, r);
        return ;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if (L <= m) update(L , R , v , lson);
    if (R > m) update(L , R , v , rson);
    PushUp(rt);
}

 

int querySUM(int L,int R,int l,int r,int rt) {  //求区间L~R的和
   if (L <= l && r <= R) {
        //printf("%d\n", sum[rt]);
       return SUM[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    int ret = 0;
    if (L <= m) ret += querySUM(L , R , lson);
    if (m < R) ret += querySUM(L , R , rson);
    return ret;
}

int queryMIN(int L,int R,int l,int r,int rt) {  //求区间L~R的最小值
    if (L <= l && r <= R) {
       //printf("%d\n", sum[rt]);
        return MIN[rt];

   }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    int ret = INF;
    if (L <= m) ret = min(ret, queryMIN(L , R , lson));
    if (m < R) ret = min(ret,queryMIN(L , R , rson));
    return ret;
}

int queryMAX(int L,int R,int l,int r,int rt) {  //求区间L~R的最大值
    if (L <= l && r <= R) {
       //printf("%d\n", sum[rt]);
        return MAX[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    int ret = -INF;
    if (L <= m) ret = max(ret, queryMAX(L , R , lson));
    if (m < R) ret = max(ret,queryMAX(L , R , rson));
    return ret;
}
int A[5000];
 int main()
 {
 	int n;
 	int k;
 	int sum;
    while(cin>>n)
 	{
 		k=0;
	 	build(1,n,1);
	 	for(int i=1;i<=n;i++)
	 	    cin>>A[i];
        for(int i=1;i<=n;i++)
		{
			k+=querySUM(A[i]+1+1,n,1,n,1);
			update(A[i]+1,A[i]+1,1,1,n,1);
		} 
		sum=k;
		for(int i=1;i<=n;i++)
		{
			k=k-A[i]+n-1-A[i];
			sum=min(sum,k);
		}
		cout<<sum<<endl;
    }
 } 

就算数据不是0-N,离散化一下就好了

int A[1001000];
struct nod
{
	int data;
	int ind;
} B[1001000];
int cmp(nod A,nod B)
{
	return A.data<B.data?true:false;
}
map < int,int>map0;
 int main()
 {
 	int n;
 	int k=0;
 	int sum;
    cin>>n;
    build(1,n,1);
    for(int i=1;i<=n;i++)
    {
    	cin>>A[i];
    	B[i].data=A[i];
    	B[i].ind=i;
    }
    sort(B+1,B+1+n,cmp);
    int d=0;
	for(int i=1;i<=n;i++)
    {
    	if(map0[B[i].data]>0)
    	{
	    	A[B[i].ind]=d;
	    }
	    else
	    {
	    	d++; 
    		A[B[i].ind]=d;
    	}
   	    map0[B[i].data]++;
    }//离散化
    
 } 

归并排序:

树状数组:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set> 
using namespace std; 

int sum[200050];
int A[200050];
int n;
int lowbit(int x)
{
	return x&(-x);
} //返回最小的值

void update(int pos,int val)//单点修改 
{
	while(pos<=n)
	{
		sum[pos]+=val;
		pos+=lowbit(pos);
	}
}//维护的是前缀和 

int query(int pos)
{
	if(pos==0)return 0;
	int s=0;
	while(pos)
	{
		s+=sum[pos];
		pos-=lowbit(pos);
	}
	return s;	
}//就算是前面的更新,也只是把需要用到的更新了,求区间和的时候需要按1的位置加起来。 

int main()
{
    while(cin>>n)
    {
       int pre;
       int tot=0;
       memset(sum,0,sizeof(sum));
	   for(int k=1;k<=n;k++)
   	   {
   	      scanf("%d",&pre);
   	      A[k]=pre;
   	      update(pre+1,1);
   	      tot+=query(n)-query(pre+1);
   	   }
   	   int k=tot;
   	   for(int i=1;i<=n;i++)
	   {
	   		k=k-A[i]+n-1-A[i];
	   		tot=min(tot,k);
	   }
	//   cout<<k<<endl;
   	   cout<<tot<<endl;
    }
}

 

UESTC 2018 Summer Training #4 Div.2 的E题

重头戏。

Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partner to be clever too (although he's not)! Parmida has prepared the following test problem for Pashmak.

There is a sequence a that consists of n integers a1, a2, ..., an. Let's denote f(l, r, x) the number of indices k such that: l ≤ k ≤ r and ak = x. His task is to calculate the number of pairs of indicies i, j (1 ≤ i < j ≤ n) such that f(1, i, ai) > f(j, n, aj).

Help Pashmak with the test.

Input

The first line of the input contains an integer n (1 ≤ n ≤ 106). The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109).

Output

Print a single integer — the answer to the problem.

Examples

Input

7
1 2 1 1 2 2 1

Output

8

Input

3
1 1 1

Output

1

Input

5
1 2 3 4 5

Output

0

这道题和上面那道题类似。离散化了一下下。(但是发现不离散化照样能过...但还是写一下:这题离散化要求度不高数据还是太小,有点卡MAP,我写的第一遍读错题所以疯狂MAP然后就T了)MAP是logN的尽量不要反复调用。

主要用C【】记录一下1`i之前出现的次数,map1[a[I]]是总次数,相减加1才是j~n的次数,查找比这个次数打得,从次数+1到N查找即可。和上面那题求逆序列一样。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include<map> 
 
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

const int maxn = 1001000;
const int INF=0x7fffffff;

using namespace std;

int lazy[maxn<<2];
int MAX[maxn<<2];
int MIN[maxn<<2];
int SUM[maxn<<2];

void PushUp(int rt) { //由左孩子、右孩子向上更新父节点
    SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
    MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]);
    MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}

void PushDown(int rt,int m) { //向下更新
    if (lazy[rt]) { //懒惰标记
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        SUM[rt<<1] = (m - (m >> 1)) * lazy[rt];
        SUM[rt<<1|1] = ((m >> 1)) * lazy[rt];
        MAX[rt<<1]=MAX[rt<<1|1]=lazy[rt];
        MIN[rt<<1]=MIN[rt<<1|1]=lazy[rt];
        lazy[rt] = 0;
   }
}

//所有的l,r,rt  带入1,n,1

void build(int l,int r,int rt) { //初始化建树
    lazy[rt] = 0;
    if (l== r) {
        SUM[rt]=MAX[rt]=MIN[rt]=0;  //初始化为0的建树
        /*scanf("%d",&SUM[rt]);  //边读入边建树的方法
          MAX[rt]=MIN[rt]=SUM[rt];
        */
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(rt);
}

void update(int L,int R,int v,int l,int r,int rt) { //将L~R区间的值置为v
    //if(L>l||R>r) return;
    if (L <= l && r <= R) {
        lazy[rt] = v;
        SUM[rt] = v * (r - l + 1);
        MIN[rt] = v;
        MAX[rt] = v;
        //printf("%d %d %d %d %d\n", rt, sum[rt], c, l, r);
        return ;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if (L <= m) update(L , R , v , lson);
    if (R > m) update(L , R , v , rson);
    PushUp(rt);
}

int querySUM(int L,int R,int l,int r,int rt) {  //求区间L~R的和
    if (L <= l && r <= R) {
        //printf("%d\n", sum[rt]);
        return SUM[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    int ret = 0;
    if (L <= m) ret += querySUM(L , R , lson);
    if (m < R) ret += querySUM(L , R , rson);
    return ret;
}

int queryMIN(int L,int R,int l,int r,int rt) {  //求区间L~R的最小值
    if (L <= l && r <= R) {
        //printf("%d\n", sum[rt]);
        return MIN[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    int ret = INF;
    if (L <= m) ret = min(ret, queryMIN(L , R , lson));
    if (m < R) ret = min(ret,queryMIN(L , R , rson));
    return ret;
}

int queryMAX(int L,int R,int l,int r,int rt) {  //求区间L~R的最大值
    if (L <= l && r <= R) {
        //printf("%d\n", sum[rt]);
        return MAX[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    int ret = -INF;
    if (L <= m) ret = max(ret, queryMAX(L , R , lson));
    if (m < R) ret = max(ret,queryMAX(L , R , rson));
    return ret;
}
int A[1001000];
int C[1001000];
struct nod
{
	int data;
	int ind;
} B[1001000];
int cmp(nod A,nod B)
{
	return A.data<B.data?true:false;
}
map < int,int>map0;
map < int,int>map1;
int D[1001000];
int E[1001000];
 int main()
 {
 	int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	scanf("%d",&A[i]);
    }
    for(int i=1;i<=n;i++)
    {
        map1[A[i]]++; 
    	C[i]=map1[A[i]];
    }
	build(1,n,1);
    long long sum=0;
    int pre;
    memset(D,0,sizeof(D));
	for(int i=1;i<=n;i++)
	{
		sum+=querySUM(map1[A[i]]-C[i]+1+1,n,1,n,1);
		pre=querySUM(C[i],C[i],1,n,1);
		update(C[i],C[i],++pre,1,n,1);
	}
	cout<<sum<<endl;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值