你正一家大型的快餐餐厅的巨型灶台上烹饪。这个灶台上有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];
}