zoukankan      html  css  js  c++  java
  • JOI2017FinalE 縄

    Link

    结论1:在最优解的情况下,绳子每一段最多只会被染一次色。

    证明:
    我们给某一段染色一定是为了跟某个位置匹配以确保接下来能够对折。
    可以将所情况抽象为:我们把(a)染成(b),折到(b)上,再把此时宽度为(2)(b)染成(c)上,代价为(3)
    那么我们如果一开始就把(a,b)染成(c),我们可以完成这样的对折,但是代价仅为(2)
    因此每段绳最多被染一次色。

    结论2:如果绳子每一段最多只被染一次色,那么最开始染一定不会比在中途染更劣。

    证明:由结论1显然。
    又因为绳子最后剩下两种颜色,所以我们需要在最开始把绳子染成两种颜色,使得这个绳子可以按题意折成长度为(2)的绳子。

    结论3:绳子可以按题意折成长度为(2)的绳子的充要条件是绳子上的所有极大颜色连续段(下文简称颜色块)除最左边和最右边的两个颜色块以外长度都为偶数。

    证明:
    先证充分性:
    我们先把最左边的颜色块长度折为1。
    然后不断地重复:“把最右边的颜色块的长度折为1,在右数第二个的颜色块的中心对折“这一操作。
    最后会剩下两个颜色块,左边长度为1,右边长度为最开始左数第二个颜色块的长度除以2。
    我们再把右边这个颜色块的长度折为1即可。
    再证必要性:
    我们采用反证法:
    假如中间有许多段长度为奇数。
    在经过多次对折之后,一定会留下:?奇?这样一段。
    此时不管怎么继续对折,中间这一段长度为奇数的颜色块都无法继续对折了。
    因此若中间存在长度为奇数的颜色段,我们一定不能按题意折成长度为(2)的绳子。
    由这个结论,我们可以得到一个新的结论:

    结论4:所有同色颜色块的首位奇偶性相同。

    证明:由结论3显然。
    那么我们可以先枚举最终必须存在的一种颜色,然后枚举这种颜色的颜色块的首位的奇偶性。
    具体而言:
    如果要求颜色块的首位是奇数,那么每个结束位置为奇数的这种颜色的颜色块都需要向后扩展一格,每个开始位置为偶数的这种颜色的颜色块都需要向前扩展一格。
    如果要求颜色块的首位是偶数,那么每个结束位置为偶数的这种颜色的颜色块都需要向后扩展一格,每个开始位置为奇数的这种颜色的颜色块都需要向前扩展一格。
    并且(1)这个位置不能向前拓展,(n)这个位置不能向后拓展。
    拓展完之后,剩下的位置全部改成在剩下的位置中出现次数最多的颜色即可。
    然后我们考虑如何实现。
    记录所有颜色出现的位置,维护每种颜色的位置数目(cnt),以及颜色的位置数目的桶(t),以及出现最多的颜色出现了多少次((mx))。
    然后枚举颜色(i),把(col[0])(col[n+1])都设为(i)
    先记录颜色为(i)的位置个数(s)
    然后把所有颜色为(i)的位置的颜色去掉,并且对于颜色为(i)的位置(x),如果(col[xoplus1] e i),那么我们把(col[xoplus1])改为(i)(并不需要改动(col)数组,更新(cnt,t,mx)即可),这对应的是颜色(i)的所有颜色块的首位为偶数的情况。
    那么这种情况下的答案就是(n-mx-s)
    然后为了不对另一种情况造成影响,我们把所有(col[xoplus1])改成(i)了的改回来。
    再考虑颜色(i)的所有颜色块的首位为奇数的情况。
    对于颜色为(i)的位置(x),如果(col[((x-1)oplus1)+1] e i),那么我们把(col[((x-1)oplus1)+1])改为(i)。(代码是暴力判断)
    再把这种情况下的答案对上面那种情况下的答案取最小值。
    最后把所有去掉颜色的和改了颜色的改回来。

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    int st[11];
    int read(){int x=0;char c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
    void write(int x){if(!x)putchar('0');int top=0;while(x)st[++top]=x%10,x/=10;while(top)putchar(st[top--]+48);putchar('
    ');}
    int min(int a,int b){return a<b? a:b;}
    const int N=1000007;
    int col[N],cnt[N],t[N],n,m,mx,ans;
    vector<int>pos[N];
    void add(int x){--t[cnt[x]],++t[++cnt[x]];if(mx<cnt[x])mx=cnt[x];}
    void mns(int x){--t[cnt[x]],++t[--cnt[x]];if(!t[mx])--mx;}
    int main()
    {
        freopen("string.in","r",stdin),freopen("string.out","w",stdout);
        n=read(),m=read();int i,j,s;
        for(i=1;i<=n;++i)col[i]=read(),add(col[i]),pos[col[i]].pb(i);
        for(i=1;i<=m;++i)
        {
    	col[0]=col[n+1]=i,s=pos[i].size();
    	for(j=1;j<=s;++j)mns(i);
    	for(int x:pos[i])if(col[x^1]^i)mns(col[x^1]);
    	ans=n-s-mx;
    	for(int x:pos[i])if(col[x^1]^i)add(col[x^1]);
    	for(int x:pos[i])if(x&1){if(col[x+1]^i)mns(col[x+1]);}else{if(col[x-1]^i)mns(col[x-1]);}
    	write(min(ans,n-s-mx));
    	for(int x:pos[i])if(x&1){if(col[x+1]^i)add(col[x+1]);}else{if(col[x-1]^i)add(col[x-1]);}
    	for(j=1;j<=s;++j) add(i);
        }
    }
    
  • 相关阅读:
    域运算符::
    类和结构体类型的异同
    4 链表组件(817)
    2 旋转链表(61)
    1、重排链表(力扣143)
    子字符串排序的关键代码
    C语言四舍五入
    约分
    python学习第八天
    python学习第七天
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12274158.html
Copyright © 2011-2022 走看看