• 「UVA10810」Ultra-QuickSort 解题报告


    题面

    看不懂?!

    大概的意思就是:

    给出一个长度为n的序列,然后每次只能交换相邻的两个数,问最小需要几次使序列**严格上升 **

    不断读入n,直到n=0结束

    思路:

    交换相邻的两个数,这不就类似冒泡排序吗?但是n<500000

    算了吧,我回去颓A+B

    于是我们就发现用冒泡排序直接计算次数是行不通的

    但我们要知道:

    冒泡排序的交换次数就是序列的逆序对数!!!

    所以——就简单了吧~

    如何求逆序对?

    较easy版的逆序对

    1、归并排序

    思想是分治法

    不断划分为两小段

    然后依次由小序列合并为大序列,同时求出逆序数

    2、树状数组

    因为树状数组的修改查询是log级的所以可以使用(前缀和的方法),没学的建议先去学习一下,不是很难

    Code:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    struct node{
    	int x,i;
    }a[500010];
    int n;
    int b[500010];
    int f[500010];
    ll ans;
    int read()
    {
    	int s=0;
    	char c=getchar();
    	while(!isdigit(c))
    		c=getchar();
    	while(isdigit(c))
    	{
    		s=(s<<1)+(s<<3)+c-'0';
    		c=getchar();
    	}
    	return s;
    }
    void update(int x)//修改
    {
    	for(;x<=n;x+=x&(-x))
    		f[x]++;
    	return;
    }
    ll sum(int x)//求前缀和
    {
    	ll res=0;
    	for(;x;x-=x&(-x))
    		res+=f[x];
    	return res;
    }
    bool cmp(node a,node b)
    {
    	return a.x>b.x;
    }
    int main()
    {
    	int i,j;
    	n=read();
    	while(n)
    	{
    		ans=0;
    		memset(f,0,sizeof(f));
    		for(i=1;i<=n;i++)
    		{
    			a[i].x=read();
    			a[i].i=i;
    		}
    		sort(a+1,a+n+1,cmp);
    		for(i=1;i<=n;i++)//先hash一下,按数值给其标记,方便后面求逆序对
    			b[a[i].i]=i;
    		for(i=1;i<=n;i++)
    		{
    			update(b[i]);//一步一做
    			ans+=sum(b[i]-1);
    		}
    		printf("%lld
    ",ans);
    		n=read();
    	}
    	return 0;
    }
    
  • 相关阅读:
    Codeforces 1485C Floor and Mod (枚举)
    CodeForces 1195D Submarine in the Rybinsk Sea (算贡献)
    CodeForces 1195C Basketball Exercise (线性DP)
    2021年初寒假训练第24场 B. 庆功会(搜索)
    任务分配(dp)
    开发工具的异常现象
    Telink MESH SDK 如何使用PWM
    Telink BLE MESH PWM波的小结
    [LeetCode] 1586. Binary Search Tree Iterator II
    [LeetCode] 1288. Remove Covered Intervals
  • 原文地址:https://www.cnblogs.com/hovny/p/10133179.html
Copyright © 2020-2023  润新知