1. 程式人生 > >省選專練之 CERC2017 Kitchen Knobs 炸雞店

省選專練之 CERC2017 Kitchen Knobs 炸雞店

你正一家大型的快餐餐廳的巨型灶臺上烹飪。這個灶臺上有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];
}