zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    java01 java基础知识
    01 开发准备 启动PHP服务与环境配置
    Axure 9.0 使用教程2-函数分类
    Axure 9.0 使用教程1-软件概述
    Python 字符串 列表 元组 字典 集合学习总结
    Python 函数定义 调用 迭代器 生成器 递归和推导式
    Python习题
    Python 条件 循环 及其他语句
    Python 字典
    Python 字符串
  • 原文地址:https://www.cnblogs.com/wlw-x/p/12662592.html
Copyright © 2011-2022 走看看