zoukankan      html  css  js  c++  java
  • 【BZOJ】3427: Poi2013 Bytecomputer

    题意:

    给定一个长度为(n)({-1, 0, 1})组成的序列,你可以进行(x_i=x_i+x_{i-1})这样的操作,求最少操作次数使其变成不降序列。((n le 1000000)

    分析:

    我们考虑第(i)个数,如果(x_i < x_{i-1}),要想(x_i ge x_{i-1}),那么(x_i)至少要加一次(x_{i-1})才能大过(x_{i-1})(当然(x_{i-1} < 0)那么永远不可能了)。

    题解

    然后我们猜测,最终的最优序列也一定由(\{-1, 0, 1\})三个数组成。我们来证明一下:
    假设第一个不是(\{-1, 0, 1\})数的位置为(p),且假设(p < n),则容易知道(x_p > 1)。当(x_{p+1} = -1)时,我们要加2次才能大于等于(x_p),当(x_{p+1}=0或1)时,我们要加1次。而由于(x_p > 1),那么说明(x_p)也一定能够等于(1),这是因为(x_{p-1})必然等于(1)(否则(x_p)就不会大于(1))。而当(x_p=1)时,对于(x_{p+1} in \{-1, 0, 1\})我们分别只需要加2次、加1次和加0次就能满足(x_{p+1} ge x_p)。显然比(x_p > 1)要优。得证。
    于是我们设(d[i, j])表示前(i)个元素当前元素为(j)时的最少操作次数,然后推一下就行了..

    #include <bits/stdc++.h>
    using namespace std;
    const int oo=~0u>>1;
    int n, d[2][3];
    
    int main() {
    	scanf("%d", &n);
    	int x; scanf("%d", &x);
    	int *now=d[0], *last=d[1];
    	last[0]=last[1]=last[2]=oo;
    	if(x==-1) last[0]=0;
    	if(x==0) last[1]=0;
    	if(x==1) last[2]=0;
    	for(int i=2; i<=n; ++i) {
    		scanf("%d", &x);
    		now[0]=now[1]=now[2]=oo;
    		if(last[0]!=oo) {
    			now[0]=last[0]+x+1;
    			if(x>=0) now[1]=last[0]+x;
    			if(x==1) now[2]=last[0];
    		}
    		if(last[1]!=oo) {
    			if(x==0) now[1]=min(now[1], last[1]);
    			if(x==1) now[2]=min(now[2], last[1]);
    		}
    		if(last[2]!=oo) {
    			now[2]=min(now[2], last[2]+1-x);
    		}
    		swap(now, last);
    	}
    	swap(now, last);
    	int ans=min(min(now[0], now[1]), now[2]);
    	if(ans==oo) puts("BRAK");
    	else printf("%d
    ", ans);
    	return 0;
    }
  • 相关阅读:
    321list,元组,range**数字是不可迭代的!
    320作业
    320基础数据类型初始
    319作业
    316作业
    319 Python基础之格式化输出、逻辑运算符、编码、in not in、while else、
    windows查看端口占用指令
    2016年学习计划
    刷算法的时候有没有必要自写测试用例?
    我们为什么不能只用O记号来谈论算法?
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4985818.html
Copyright © 2011-2022 走看看