• Daliy Algorithm(线段树&组合数学) -- day 53


    Nothing to fear

    those times when you get up early and you work hard; those times when you stay up late and you work hard; those times when don’t feel like working — you’re too tired, you don’t want to push yourself — but you do it anyway. That is actually the dream. That’s the dream. It’s not the destination, it’s the journey. And if you guys can understand that, what you’ll see happen is that you won’t accomplish your dreams, your dreams won’t come true, something greater will. mamba out


    那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

    2020.4.8


    逆序对

    使用线段树求解逆序对
    思路: 散列 hash
    借助树状数组或者线段树帮助序列进行求解逆序对
    即查找当前元素前面大的数存在多少
    注意:

    1. 数组必须开到数列当中最大元素的大小
    2. 如果数组太大就采用离散化
    /*
    
    思路:
    1. hash 散列 构造一个hash表 长度要和最大
       注意再进行计算逆序对数量的时候要用 i - query(1 , 1 ,a[i]);
    
    
    2. 如果出现的数字过大超出了最大申请空间范围
    思路 : 离散化
    
    */
    
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int N = 100005;
    
    struct node{
    	int l , r ,cnt;
    }tr[N * 4];
    
    int a[N];
    int n , mx;
    void pushup(int u)
    {
    	tr[u].cnt = tr[u << 1].cnt + tr[u << 1 | 1].cnt;
    }
    
    void build(int u ,int l ,int r)
    {
    	if(l == r)
    	{
    		tr[u].l = l, tr[u].r = r;
    		tr[u].cnt = 0;
    	}else{
    		tr[u].l = l, tr[u].r = r;
    		int mid = l + r >> 1;
    		build(u << 1 , l, mid);
    		build(u << 1 | 1, mid + 1 , r);
    		pushup(u);
    	}
    }
    
    int query(int u, int l ,int r)
    {
    	if(tr[u]. l >= l && tr[u].r <= r)
    	{
    		return tr[u].cnt;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	int ans = 0;
    	if(l <= mid)ans = query(u << 1 , l , r);
    	if(r > mid) ans+= query(u << 1 | 1 , l , r);
    	return ans; 
    }
    
    void modify(int u ,int x , int  v)
    {
    	if(tr[u].l == tr[u].r)
    	{
    		tr[u].cnt += v;
    	}else{
    		int mid = tr[u].l + tr[u].r >> 1;
    		if(x <= mid) modify(u << 1 , x , v);
    		else modify(u << 1 | 1, x , v);
    		pushup(u); 
    	}
    }
    
    int main()
    {
    	cin >> n;
    	for(int i = 1;i <= n ;i ++){
    		scanf("%d",&a[i]);
    		mx = max(mx,a[i]);
    	}
    
    	build(1 , 1 , mx);
    	int ans = 0;
    	for(int i = 1;i <= n ;i ++)
    	{
    		modify(1 , a[i] , 1);
    		ans += (i - query(1, 1 , a[i]));
    	}
    	cout << ans << endl;
    	return 0;
    }
    

    鸣人的影分身

    实际上是组合数学当中的m个苹果放n个盘子问题
    一共有如下几种情况:

    1. 就剩一个盘子 或者 没有苹果的时候 只有一种方案
      if(x == 0 || y == 1)return 1;
    2. 如果盘子数 > 苹果数 那么多出来的盘子必定不会放苹果所以舍弃
      if(y > x)
      f(x , x);

    3.如果苹果数 > 盘子数:
    1. 存在空盘子
    即至少有一个盘子为空
    f(x , y - 1);
    2. 不存在空盘子
    即每个盘子最少分一个
    f(x - y , y);

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    
    using namespace std;
    const int N = 15;
    int f[N][N];
    int t , m, n;
    
    // 查克拉 苹果
    // 影分身 盘子
    int dfs(int x , int y)
    {
    	if(f[x][y] != -1)return f[x][y];
    	if(x == 0 || y == 1)return 1; // 当当前苹果数量为零 或者 当前盘子数量为 1 只有一种方案
    	if(y > x)return dfs(x , x);   // 如果当前盘子的个数大于苹果的个数 那么剩下的盘子也没用我们最多只用 x 个盘子
    	return f[x][y] = dfs(x-y, y) + dfs(x , y-1);
    }
    int main()
    {
    	cin >> t;
    	while(t--)
    	{
    		memset(f, -1 , sizeof f);
    		cin >> m >> n;
    		cout << dfs(m , n) << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    【沟通的艺术】你能勾住你的听众么?
    java环境变量配置
    20140613故障处理纪要
    FBReaderJ源代码编译配置
    怎样加入� android private libraries 中的包的源码
    petshop4.0 具体解释之中的一个(系统架构设计)
    java推断字符串是否为乱码
    php递归无限极分类
    SIP入门(二):建立SIPserver
    线程间的通信
  • 原文地址:https://www.cnblogs.com/wlw-x/p/12662592.html
Copyright © 2020-2023  润新知