省选专练之 CERC2017 Kitchen Knobs 炸鸡店

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/82710603

你正一家大型的快餐餐厅的巨型灶台上烹饪。这个灶台上有n个炉子排成一排,并按序标为1-n号。每个炉子都会被它的控制手柄所控制。这些手柄可不一般:每个手柄上面都有1-7的号码围成一圈。灶台的火力就是从它的控制手柄顶端开始顺时针读取数字而得到的。

每一步你都可转动一个或多个相邻手柄——向任意方向转动任意几下。但是,同一步转动的手柄只能向同一方向转动同样的次数。

找到最少的步数来吧所有的炉子都设定到可能的最大火力。

思维难题,也是这场比赛的金牌题

但你说考不能考到NOIP呢?也不是不行

这道题考察了泛化物品这个概念和差分的应用(这不都是NOIP知识点吗)

第一发现只需要顺时针转动。(逆时针等于顺时针+7)

此时问题转化为了:对一段进行区间加和取膜(7)使这段区间变为全零。

似乎发现全零是单点的,所以考虑对序列差分

此时转化为对差分序列进行单点修改是他变为全0

考虑配对1-6 2-5 3-4

这些东西为什么是对的?

原因是1差分是-1+1而这使6变成7则合法了

然后剩下找最多的全零组。

一个加起来对7取mod的值为0的组称之为全0组

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+100;
typedef int INT;
#define int short
inline void up(int&a,int b){a>b?(a=b):0;}
const int INF=1e4+7;
inline int Get(char *S){
    int l=0,r=1,len=0;
    while(l<7&&r<7&&len<7){
        int t=S[(l+len)%7]-S[(r+len)%7];
        if(t==0){
            len++;
        }
        else{
            if(t<0){
                l+=(len+1);
            }
            else r+=(len+1);
            if(l==r)r++;
            len=0;
        }
    }	
    int now=-1;
    for(int i=1;i<7;++i){
        if(S[i]!=S[i-1])now=1;
    }
    if(now==-1)return now;
    return min(l,r);
}
char S[N];
int v[N];
int n;
int cnt[7];
struct Node{
    int a,b,c,v;
}e[N];
int tot=0;
int F[501][501][501];
int ans=0;
int A,B,C;
int x,y,z;
INT main(){
//	freopen("test.in","r",stdin);
    INT Cas;
    scanf("%d",&Cas);
    while(Cas--){
        scanf("%s",S);
        int sum=Get(S);
        if(sum>=0)v[++n]=sum;
    }
    for(int i=n+1;i;--i)v[i]-=v[i-1];
    for(int i=1;i<=n+1;++i)(v[i]=(v[i]+7)%7);
    n++;
    for(int i=1;i<=n;++i)++cnt[v[i]];
    while(cnt[1]&&cnt[6])cnt[1]--,cnt[6]--,ans++;
    A=cnt[1]?cnt[1]:cnt[6];
    x=cnt[1]?1:6;
    while(cnt[2]&&cnt[5])cnt[2]--,cnt[5]--,ans++;
    B=cnt[2]?cnt[2]:cnt[5];
    y=cnt[2]?2:5;
    while(cnt[3]&&cnt[4])cnt[3]--,cnt[4]--,ans++;
    C=cnt[3]?cnt[3]:cnt[4];
    z=cnt[3]?3:4;
    for(int i=0;i<=7;++i){
        for(int j=0;j<=7;++j){
            for(int k=0;k<=7;++k){
                if(i+j+k&&(i*x+j*y+k*z)%7==0){
                    ++tot;
                    e[tot].a=i;
                    e[tot].b=j;
                    e[tot].c=k;
                    e[tot].v=i+j+k-1;
                }
            }
        }
    }
    for(int i=0;i<=A;++i){
        for(int j=0;j<=B;++j){
            for(int k=0;k<=C;++k){
                if(i+j+k){
                    int sum=INF;
                    for(int t=1;t<=tot;++t){
                        if(i>=e[t].a&&j>=e[t].b&&k>=e[t].c){
                            up(sum,F[i-e[t].a][j-e[t].b][k-e[t].c]+e[t].v);
                        }
                    }
                    F[i][j][k]=sum;					
                }
            }
        }
    }
    cout<<ans+F[A][B][C];
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/82710603