• 模拟 [D. Colorful Points ]


    模拟 D. Colorful Points

    题目大意:

    给你一个字符串,对于一个字符,如果左右两边的字符和这个不一样,那么就删除这个字符,一次可以删去多个字符,问最少的删除次数,使得不能再删。

    题解:

    这个是一个模拟题,写起来感觉挺恶心的,但是也很考验写题的技巧,用好的技巧写就显得很简洁。

    按照网上的一个思路写的,首先证明一下这个解题思路:

    假设有k个不同的块(每一块都是相同的),那么每次删除 (2*(k-1)) 个数,所以一共遍历 (frac{n}{2*(k-1)}) ,每次遍历的复杂度是 (O(k)) ,所以总的复杂度是 (k*frac{n}{2*(k-1)})

    写法:

    因为最后的形式是 (aaaabbbccababa) ,那么可以等价于 ([4a,3b,2c,1a,1b,1a,1b,1a])

    然后很容易发现,每次操作如果是左右两边的块就 (-1) ,如果是中间的块就 (-2) ,所以每次操作完之后就可以重新合并一次,因为有些块删除之后,两边的块可以连在一起。

    这个合并函数可以记录学习一下,以后碰到类似的可以使用这种方法:

    void cal(){
    	int len = n;
    	n = 0;
    	for(int i=1;i<=len;i++){
    		if(e[i].num>0){
    			if(e[i].val==e[n].val) e[n].num += e[i].num;
    			else e[++n]=e[i];
    		}
    	}
    }
    

    (CODE:)

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define debug(x) cout<<"debug:"<<#x<<" = "<<x<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    struct node{
    	int val,num;
    	node(int val=0,int num=0):val(val),num(num){}
    }e[maxn];
    char s[maxn];
    int n;
    void cal(){
    	int len = n;
    	n = 0;
    	for(int i=1;i<=len;i++){
    		if(e[i].num>0){
    			if(e[i].val==e[n].val) e[n].num += e[i].num;
    			else e[++n]=e[i];
    		}
    	}
    }
    
    void solve(){
    	int ans = 0;
    	while(n>1){
    		for(int i=2;i<n;i++) e[i].num -=2;
    		e[1].num--,e[n].num--;
    		ans++;
    		cal();
    	}
    	printf("%d
    ", ans);
    }
    int main(){
    	scanf("%s",s+1);
    	n = strlen(s+1);
    	e[0].val = -1;
    	for(int i=1;i<=n;i++) e[i].val = s[i]-'a',e[i].num = 1;
    	cal();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    Python导学基础(三)输入、格式化输出、基本运算符
    题解-FJOI2014 树的重心
    题解-CF1307G Cow and Exercise
    题解-SHOI2005 树的双中心
    笔记-CF643E Bear and Destroying Subtrees
    题解-CF643G Choosing Ads
    扩展Lucas
    线性筛筛积性函数
    整除分块(数论)
    2019暑假集训DAY17(problem2.b)(杜教筛)
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13490849.html
Copyright © 2020-2023  润新知