绍兴一中模拟赛3.21——孰是孰非

博客围绕一个长为n(n≤500)的序列展开,每次可对一段区间加x,大于7则减7。目标是让所有元素等于7,求解最少操作次数。先进行差分,将操作转化,发现部分数可抵消,最后采用dp求解,复杂度为O(7⋅(6n)3)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

有一个长为n(n≤500)n(n≤500)n(n500)的序列,每次可以选一段区间加上xxx,如果有数大于777就减777(保持所有数∈[1,7]∈[1,7][1,7]
问:最少几次这样的操作才能使所有aia_iai都等于777

Solution

step1:step1:step1先差分一下,令bi=ai−ai−1(1≤i≤n+1,a0=an+1=0)b_i=a_i-a_{i-1}(1≤i≤n+1,a_0=a_{n+1}=0)bi=aiai1(1in+1,a0=an+1=0)
每次操作就变成bl+xb_l+xbl+xbr+1−xb_{r+1}-xbr+1x,目的是让所有bi=0b_i=0bi=0
step2:step2:step2我们发现111666是可以一次抵消掉的,同理,222555333444也一样
暴力消的话,也最多消数的个数次就行
step3:dpstep3:dpstep3dp
因为111666222555333444每对都有一个数被抵消掉了,所以dpdpdp状态只要四维就行(第四维是记录当前这些数的和)
f[i][j][k][l]f[i][j][k][l]f[i][j][k][l]表示已经用了iii1/61/61/6jjj2/52/52/5kkk3/43/43/4,总和mod7mod7mod7lll时,最多能少几个步骤,转移见代码
复杂度O(7⋅(n6)3)O(7\cdot(\frac{n}{6})^3)O(7(6n)3)

Code

#include<bits/stdc++.h>
using namespace std;
int n,x,y,z,i,mx,my,mz,l,j,k,a[8],f[2][502][502][7],las,ans,p;
void Max(int &x,int y){if(y>x)x=y;}
int main(){
	scanf("%d",&n);
	for (i=1;i<=n;i++){
		scanf("%d",&x);
		a[(x-las+7)%7]++,las=x;
	}
	a[7-las]++;
	if (a[1]>a[6]) x=1,swap(a[1],a[6]);
	else x=6;
	if (a[2]>a[5]) y=2,swap(a[2],a[5]);
	else y=5;
	if (a[3]>a[4]) z=3,swap(a[3],a[4]);
	else z=4;
	ans=a[4]+a[5]+a[6];
	mx=a[6]-a[1],my=a[5]-a[2],mz=a[4]-a[3];
	for (i=0;i<=mx;i++,p^=1)
		for (j=0;j<=my;j++)
			for (k=0;k<=mz;k++)
				for (l=0;l<7;l++)
				Max(f[p^1][j][k][(l+x)%7],f[p][j][k][l]+(l+x==7)),
				Max(f[p][j+1][k][(l+y)%7],f[p][j][k][l]+(l+y==7)),
				Max(f[p][j][k+1][(l+z)%7],f[p][j][k][l]+(l+z==7));
	printf("%d",ans-f[p^1][my][mz][0]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值