• LOJ2336 JOI2017 绳 贪心、构造


    传送门


    首先显然的是可以一开始先染好再做、每个点只会被染一次、最后只剩下两种颜色。

    接下来是结论时间:序列可以反转的充要条件是除了首尾的极大颜色连通块以外其他极大颜色连通块长度为偶数。


    证明充分性:考虑归纳。

    如果序列中有(3)个极大颜色连通块且中间的连通块长度为偶数,那么先将两端的颜色块折成(1),然后沿着中间块的中线对折,然后把较大的块折成(1)即可满足条件。

    如果序列中有(x>3)个极大颜色连通块,则把尾部的极大颜色连通块长度折成(1)然后沿着倒数第二个颜色块的中线对折,可以得到一个有(x-1)个极大颜色连通块的局面。

    由归纳可知假设成立。


    证明必要性:仍然考虑归纳。

    如果序列中有(1)个非首尾极大颜色连通块长度为奇数,那么无论如何这个奇数的连通块和与其相邻的连通块无法被对折,所以显然无解。

    如果序列中有(geq 2)个非首尾长度为奇数的极大颜色连通块,则如果进行折叠,显然不会使这样的连通块数量减少为(0)

    由归纳可知假设成立


    与上面的结论等价的结论是:同色连通块的起始位置的奇偶性相同。

    这样我们枚举每一种颜色,再枚举其起始位置的奇偶性,对于一个原序列中这样的非首尾极大连通块,如果不满足条件就尽可能向前后拓展。最后维护一下非当前位置的元素中出现次数最多的颜色就可以了。

    复杂度不难做到(O(n))

    #include<bits/stdc++.h>
    using namespace std;
    
    int read(){
    	int a = 0; char c = getchar(); while(!isdigit(c)) c = getchar();
    	while(isdigit(c)){a = a * 10 + c - 48; c = getchar();}
    	return a;
    }
    
    const int _ = 1e6 + 7; vector < int > pos[_]; int arr[_] , pot[_] , sz[_] , MX , N , M;
    
    void del(int x){if(!--sz[pot[x]] && pot[x] == MX) --MX; ++sz[--pot[x]];}
    void add(int x){--sz[pot[x]]; ++sz[++pot[x]];}
    
    int main(){
    	N = read(); M = read(); if(M == 1){puts("0"); return 0;}
    	for(int i = 1 ; i <= N ; ++i){++pot[arr[i] = read()]; pos[arr[i]].push_back(i);}
    	for(int i = 1 ; i <= M ; ++i){++sz[pot[i]]; MX = max(MX , pot[i]);}
    	for(int i = 1 ; i <= M ; ++i){
    		int ans = 1e9 , p = 0 , q , now , pre = MX , S = pos[i].size(); --sz[pot[i]]; while(!sz[MX]) --MX; now = MX;
    		
    		while(p < S){
    			q = p; while(q < S && pos[i][q] - pos[i][p] == q - p) ++q;
    			if(!(pos[i][p] & 1)) del(arr[pos[i][p] - 1]);
    			if(pos[i][q - 1] != N && (pos[i][q - 1] & 1)) del(arr[pos[i][q - 1] + 1]);
    			p = q;
    		}
    		ans = min(ans , N - pot[i] - MX); MX = now; p = 0;
    		while(p < S){
    			q = p; while(q < S && pos[i][q] - pos[i][p] == q - p) ++q;
    			if(!(pos[i][p] & 1)) add(arr[pos[i][p] - 1]);
    			if(pos[i][q - 1] != N && (pos[i][q - 1] & 1)) add(arr[pos[i][q - 1] + 1]);
    			p = q;
    		}
    
    		p = 0;
    		while(p < S){
    			q = p; while(q < S && pos[i][q] - pos[i][p] == q - p) ++q;
    			if(pos[i][p] != 1 && (pos[i][p] & 1)) del(arr[pos[i][p] - 1]);
    			if(pos[i][q - 1] != N && !(pos[i][q - 1] & 1)) del(arr[pos[i][q - 1] + 1]);
    			p = q;
    		}
    		printf("%d
    " , min(ans , N - pot[i] - MX)); p = 0; MX = pre; ++sz[pot[i]];
    		while(p < S){
    			q = p; while(q < S && pos[i][q] - pos[i][p] == q - p) ++q;
    			if(pos[i][p] != 1 && (pos[i][p] & 1)) add(arr[pos[i][p] - 1]);
    			if(pos[i][q - 1] != N && !(pos[i][q - 1] & 1)) add(arr[pos[i][q - 1] + 1]);
    			p = q;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    小程序源码丢失了怎么在微信平台反编译找回
    做前端技术方案选型的时候,你是怎么做决策的?
    小程序源码丢失了怎么在微信平台反编译找回
    关于form.submit()不能提交表单的错误原因
    IE 8兼容:X-UA-Compatible的解释
    常用的CSS Hack技术集锦
    PHP制作验证码
    利用原生JavaScript获取样式的方式小结
    利用Javascript获取当前日期的农历日期
    教你利用iframe在网页中显示天气
  • 原文地址:https://www.cnblogs.com/Itst/p/11553085.html
Copyright © 2020-2023  润新知