• ICPC2020上海站F Fountains 状压


    题意:给定长为(n)的序列,定义区间([l,r])的权值(C(l,r))([l,r])中所有元素的和,现在试选择(k)个区间([l_i, r_i](1leq l_ileq r_ileq n)),使得
    $$sum_{1leq Lleq Rleq n} [C(L, R) - max_{Lleq l_i leq r_i leq R } C(l_i, r_i)]$$最小,对(k=1, 2, 3..., n*(n+1)/2)作出回答,且(nleq 9)


    不妨假定已经选择(k)个区间,考虑怎么使得权值和最小

    显然,将(k)个区间按权值大小从大到小排序,所有的([L, R])区间会按此顺序选择第一个被它包含的区间([l_i, r_i])

    换而言之,即将(k)个区间从大到小排序后,依次考虑,在仍未选择的区间([L, R])中,所有能选择([l_i, r_i])的区间一定会选择此区间

    可以(dp),状态为已经选择了(k)个区间,及仍未选择的区间

    仍未选择的区间可以通过((r_1, r_2, ..., r_n))表示,其中(r_i)表示([i, i], [i,i+1], ..., [i, r_i])仍未选择

    由于(r_1leq r_2 leq ... leq r_n),状态数并不大(最大375544),并且本题有6s时限,hash都不用,开个map即可过

    #include <map>
    #include <vector>
    #include <cstdio>
    #include <iostream>
    #include <algorithm> 
    using namespace std;
    
    #define l first
    #define r second
    #define ll long long
    #define mp make_pair
    #define pii pair <int, int>
    #define rep(io, st, ed) for(int io = st; io <= ed; io ++)
    #define drep(io, ed, st) for(int io = ed; io >= st; io --)
    
    const int sid = 1e6 + 5;
    
    int n, tt[105];
    ll all, ans[105], s[105];
    map <ll, ll> now, pre;
    vector <pii> seg;
    
    ll encode(int *a) {
    	ll ret = 0;
    	drep(i, n + 1, 1) ret = ret * 10 + a[i];
    	return ret;
    }
    
    void decode(ll v, int *a) {
    	rep(i, 1, n) a[i] = v % 10, v /= 10;
    	a[n + 1] = v;
    }
    
    int main() {
    	cin >> n;
    	rep(i, 1, n) cin >> s[i], s[i] += s[i - 1];
    	rep(L, 1, n) rep(R, L, n) seg.push_back(mp(L, R)), all += s[R] - s[L - 1];
    	sort(seg.begin(), seg.end(), [](pii &a, pii &b) { return s[a.r] - s[a.l - 1] >= s[b.r] - s[b.l - 1]; } );
    	rep(i, 1, n) tt[i] = n; now[encode(tt)] = 0;
    	rep(si, 0, seg.size() - 1) {
    		int l = seg[si].l, r = seg[si].r;
    		ll v = s[r] - s[l - 1];
    		pre = now; now.clear();
    		for(auto x : pre) {
    			ll pv = x.second; decode(x.first, tt);
    			//不选择
    			now[x.first] = max(now[x.first], pv);
    			//选择
    			rep(i, 1, l) if(tt[i] >= r) pv += (tt[i] - r + 1) * v, tt[i] = r - 1;
    			tt[n + 1] ++; ll to = encode(tt);
    			now[to] = max(now[to], pv);
    		}
    	}
    	for(auto x : now) {
    		decode(x.first, tt);
    		ans[ tt[n + 1] ] = max(ans[ tt[n + 1] ], x.second);
    	}
    	rep(i, 1, n * (n + 1) / 2) printf("%lld
    ", all - ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    鼠标不灵了,还好只是线的问题。自己DIY修下了
    [摘]编译MPlayer
    TPLINK路由器 硬重启方法
    Visual C++线程同步技术剖析 (转载)
    CListCtrl一行显示多个图标问题
    一位软件工程师的6年总结
    CCIE红头发讲解CCNA、CCNP视频教程
    图片链
    [摘]如何级联两个TPLINK路由器
    [摘]测试一下你对IP地址的掌握水平
  • 原文地址:https://www.cnblogs.com/reverymoon/p/14153891.html
Copyright © 2020-2023  润新知