zoukankan      html  css  js  c++  java
  • E. Partition Game

    E. Partition Game

    首先肯定可以想到dp

    [dp[i][j] = min(dp[p][j - 1] + val(p + 1 , i)) ]

    dp表示前i个被分成j块,那么肯定要枚举上一块的尾节点,然后算一下val(p + 1 , i)表示(p + 1 , i)这一段的贡献值是多少。

    1. 对于一段来说[L , R] , 其中不同的a[i]值贡献都是独立的

    2. 那么对于一个a[i] = x来说,其存在于X[1] , X[2] , X[3] , ..... X[m] 位置上。

      那么它的贡献等于X[m] - X[1] = X[2] - X[1] + X[3] - X[2] +......+ X[m] - X[m - 1]

      那么对于这个公式,我们只需要对每个点求一个i - last[i] , last[i] 表示 上一个a[i]出现的位置。

    3. 从最上面的dp递推公式来看,我们只需要看一下val(p + 1 , i)的贡献值,

      但是因为不是很好算,因为既需要枚举i,又需要枚举p。

      所以就直接先枚举k,然后枚举i来更新dp。

      那么怎么更新呢。

      根据2里面的公式,只需要每个点的x = i - last[i],把x加到它被h < i中需要的h上面。

      对于h >= 1 && h < last[i] , 这个部分都是需要的,因为[last[i] , i]这一对在last[i] - 1右边,可以产生贡献,但是h >= last[i] && h <= i 的这一部分不需要,因为在这个h右边,last[i]不存在。

      这就形成了区间加,并且当前dp需要最小值,所以线段树求解dp

    // #pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
    // #pragma GCC optimize(3 , "Ofast" , "inline")
    // #pragma GCC optimize("Ofast")
    // #pragma GCC target("avx,avx2,fma")
    // #pragma GCC optimization("unroll-loops")
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #include <bitset>
    #include <deque>
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0)
    #define x first
    #define y second
    #define pb push_back
    #define ls rt << 1
    #define rs rt << 1 | 1
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 37000 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    int n , m , minx[N << 2] , lazy[N << 2] , dp[N] ;
    void up(int rt) {
    	minx[rt] = min(minx[ls] , minx[rs]) ;
    }
    void down(int rt) {
    	if(lazy[rt]) {
    		lazy[ls] += lazy[rt] ;
    		lazy[rs] += lazy[rt] ;
    		minx[ls] += lazy[rt] ;
    		minx[rs] += lazy[rt] ;
    		minx[rt] = min(minx[ls] , minx[rs]) ;
    		lazy[rt] = 0 ;
    	}
    	return ;
    }
    void build(int rt , int l , int r) {
    	minx[rt] = INF , lazy[rt] = 0 ;
    	if(l == r) {
    		minx[rt] = dp[l] ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	build(ls , l , mid) ;
    	build(rs , mid + 1 , r) ;
    	up(rt) ;
    } 
    void update(int rt , int l , int r , int ql , int qr , int k) {
    	if(qr <= 0 || qr < ql) return ;
    	if(ql <= l && r <= qr) {
    		minx[rt] += k ;
    		lazy[rt] += k ;
    		return ;
    	}
    	down(rt) ;
    	int mid = l + r >> 1 ;
    	if(ql <= mid) update(ls , l , mid , ql , qr , k) ;
    	if(qr > mid) update(rs , mid + 1 , r , ql , qr , k) ;
    	up(rt) ;
    }
    int ask(int rt , int l , int r , int ql , int qr){
    	if(qr <= 0) return 0 ;
    	if(ql <= l && r <= qr) return minx[rt] ;
    	int mid = l + r >> 1 , ans = INF ;
    	down(rt) ;
    	if(ql <= mid) ans = ask(ls , l , mid , ql , qr) ;
    	if(qr > mid) ans = min(ans , ask(rs , mid + 1 , r , ql , qr)) ;
    	return ans ;
    }
    int k , a[N] , last[N] , mp[N] ; 
    int work()
    {
      cin >> n >> k ;
      for(int i = 1; i <= n ;i ++ ) {
      	cin >> a[i] ;
      	last[i] = mp[a[i]] ;
      	mp[a[i]] = i ;
      	dp[i] = dp[i - 1] ;
      	if(last[i]) dp[i] += i - last[i] ;
      }
      for(int j = 2; j <= k ; j ++ ) {
      	build(1 , 1 , n) ;
      	for(int i = j ;i <= n ;i ++ ) {
      		update(1 , 1 , n , 1 , last[i] - 1 , i - last[i]) ;
      		dp[i] = ask(1 , 1 , n , 1 , i - 1) ;
      	}
      }
      cout << dp[n] << "
    " ;
      return 0 ;
    }
    int main()
    {
      //   freopen("C://Users//spnooyseed//Desktop//in.txt" , "r" , stdin) ;
      //   freopen("C://Users//spnooyseed//Desktop//out.txt" , "w" , stdout) ;
    
      work() ;
      return 0 ;
    }
    /*
    
    */
    	
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    Mac下Intellij IDEA Console中文是?
    MAC && Linux terminal session clone
    高扩展性网站的原则
    职场感悟
    如何保持自己 fork 的项目和原始项目同步
    统一回复一下同学们的咨询
    Can't exec "aclocal": No such file or directory at /usr/share/autoconf/Autom4te/FileUtils.pm line 326.
    checking for tgetent()... configure: error: NOT FOUND!
    Simultaneous Tag Editing in IntelliJ IDEA 14.1
    Mac 配置 vim
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/14799193.html
Copyright © 2011-2022 走看看