【题解】P4749 [CERC2017]Kitchen Knobs

题目描述

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

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

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

输入输出格式

输入格式

第一行包含一个整数(1<=n<=501)表示炉子的数量。接下去第j行包含7个非零整数,其中第一个是初始火力大小。

输出格式

输出一个整数,表示需要的步数。

题解

个人觉得非常好的一道步步优化的DP题。
首先可以知道每个炉子需要多少步到最优解(全部相同的炉子舍弃掉)
这个东西区间似乎不太好做,那么我们来差分一下,而后一次操作相当与两个位置一加一减相同的数,目标是将所有数变成0。
现在有6种数,直接DP是n6
首先可以小贪心一下,在mod7意义下进行,将1和6,2和5,3和4先配对,于是现在只剩3种数,复杂度n3
完结撒花!!❀❀❀

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=510;
short f[N][N][N];
int n,a[N][9],mx[N],p[7];
int ans,v[4],w[4];
signed main(){
	n=rd();
	for(int i=1;i<=n;i++){
		a[i][1]=rd();
		if(a[i][1]%1111111==0){
			i--,n--;
			continue;
		}
		for(int j=2;j<=7;j++)a[i][j]=(a[i][j-1]%1000000)*10+a[i][j-1]/1000000;
		for(int j=1;j<=7;j++)if(a[i][mx[i]]<a[i][j])mx[i]=j;
		mx[i]--;
//		for(int j=1;j<=7;j++)cout<<a[i][j]<<" ";
//		cout<<"\n";
	}
	for(int i=1;i<=n;i++)p[(mx[i]-mx[i-1]+7)%7]++;
//	for(int i=1;i<=n;i++)cout<<mx[i]<<" ";
//	cout<<"\n";
	v[1]=(p[1]>p[6])?1:6,w[1]=abs(p[1]-p[6]);
	v[2]=(p[2]>p[5])?2:5,w[2]=abs(p[2]-p[5]);
	v[3]=(p[3]>p[4])?3:4,w[3]=abs(p[3]-p[4]);
	ans=max(p[1],p[6])+max(p[2],p[5])+max(p[3],p[4]);
	for(int i=0;i<=w[1];i++){
		for(int j=0;j<=w[2];j++){
			for(int k=0;k<=w[3];k++){
				f[i][j][k]+=((i*v[1]+j*v[2]+k*v[3])%7==0);
				f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]);
				f[i][j+1][k]=max(f[i][j+1][k],f[i][j][k]);
				f[i][j][k+1]=max(f[i][j][k+1],f[i][j][k]);
			}
		}
	}
	printf("%d\n",ans+1-f[w[1]][w[2]][w[3]]);
	return 0;
}
posted @   flywatre  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示