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\n" , 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;
}

转载于:https://www.cnblogs.com/Itst/p/11553085.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值