zoukankan      html  css  js  c++  java
  • CodeForces

    题目

    传送门

    解法

    (dp_i) 为推倒前 (i) 张骨牌的最小代价。考虑第 (i) 张骨牌向左推或不推(向右推实际上等价于后面的骨牌不推)。再设 (l_i) 为第 (i) 张骨牌向左推能推倒的最远骨牌,(r_i) 同理。

    对于向左推,我们发现这相当于将 ([l_i,i]) 中的骨牌都推倒了,所以转移直接从 (l_i-1) 继承:(dp_i=dp_{l_i-1}+w_i)

    对于不推,前面就必须有骨牌向右推倒,转移有:

    [dp_i=min_{}{f_{j-1}+w_j | j<ile r_j} ]

    但这是 (mathcal O(m^2)) 的,用线段树优化也有一个 (log),过不去。

    可以发现,若骨牌 (i) 可以推倒骨牌 (j)(不妨设 (i<j)),那么向右推倒骨牌 (i) 延伸的长度一定大于 (j) 延伸的长度。

    这和优化有什么关系呢?再清楚一点:假设能推倒 (i) 的骨牌集合为 (S_i),而 (i) 能推倒 (j),这就意味着 (S_isubseteq S_j)。这说明合法推倒集合是可以继承的!我们考虑用单调栈。

    首先根据这条法则,我们可以计算出 (l_i,r_i)

    对于不推的转移,这实际是一个取 (S_i) 中点 (j)(min_{}{f_{j-1}+w_j}) 的过程,用单调栈维护离 (i) 最近的能向右推倒它的点 (k),那么 (S_i) 就是 (S_k) 加上 (k) 这个单独元素,若令 (pre_i)(S_i) 中点 (j)(min_{}{f_{j-1}+w_j}),实际上就是 (dp_i=pre_{k})

    所以实际上并不需要维护 (r_i)

    代码

    #include <stack> 
    #include <cstdio>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    #define print(x,y) write(x),putchar(y) 
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    
    typedef long long ll;
    typedef pair <int,ll> pii;
    
    const int maxn=250005,maxl=1e7+2;
    
    int n,m,l[maxl];
    ll f[maxl],pre[maxl];
    stack <int> s;
    vector <pii> dom[maxn],d;
    
    int main() {
    	n=read(9),m=read(9);
    	for(int i=1;i<=n;++i) {
    		int k=read(9);
    		for(int j=1;j<=k;++j)
    			dom[i].push_back(make_pair(read(9),0));
    		for(int j=1;j<=k;++j)
    			dom[i][j-1].second=read(9);
    	}
    	d.push_back(make_pair(1e8,0));
    	for(int q=read(9);q;--q) {
    		int id=read(9),mul=read(9);
    		for(int i=0;i<dom[id].size();++i)
    			d.push_back(make_pair(dom[id][i].first,dom[id][i].second*mul));
    	}
    	for(int i=m;i;--i) {
    		while(!s.empty() and i<=s.top()-d[s.top()].first)
    			l[s.top()]=i+1,s.pop();
    		s.push(i);
    	}
    	while(!s.empty()) s.pop();
    	for(int i=1;i<=m;++i)
    		if(!l[i]) l[i]=1;
    	pre[0]=1e18,s.push(0);
    	for(int i=1;i<=m;++i) {
    		while(!s.empty() and d[s.top()].first+s.top()<=i)
    			s.pop();
    		f[i]=min(f[l[i]-1]+d[i].second,pre[s.top()]);
    		pre[i]=min(pre[s.top()],f[i-1]+d[i].second);
    		s.push(i);
    	}
    	print(f[m],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    爬虫大作业
    数据结构化与保存
    使用正则表达式,取得点击次数,函数抽离
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    综合练习:词频统计
    Hadoop综合大作业
    理解MapReduce
    熟悉HBase基本操作
    熟悉常用的HBase操作
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15017681.html
Copyright © 2011-2022 走看看