[51nod1357]密码锁

今年GDOI Day1T2就是这题==听说出题人是把一道原题改成另一道原题的?(雾

先把两个字符串对应位置相减,问题变为把密码锁拨成全$0$

我们可以做区间$+1$或$-1$操作,不妨在序列的开头和末尾补上两个$0$后差分,我们同样要把这$n+1$个数变成全$0$,但现在我们可以做的操作是单点$+1$和$-1$,并且需要保证$+1$和$-1$的次数一样多,因为在最优解中一个数不会被同时$+1$和$-1$,所以直接从小到大排序后贪心是可以的,直接扫一遍找到一个位置,把前面的数减到$0$,把后面的数加到$10$,并且满足操作次数相等就可以了

为什么一定可以找到这样的位置?因为如果找不到,这意味着序列中所有数的和不是$10$的倍数,而差分序列中所有数的和是最后一个数减去第一个数也就是$0$,模意义下的$0$就是$10$的倍数,就矛盾了

注意判一下一开始就相等的情况

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char s[2510],t[2510];
int d[2510],sum[2510];
int main(){
	int T,n,i,ts;
	scanf("%d",&T);
	while(T--){
		scanf("%s%s",s+1,t+1);
		n=strlen(s+1)+1;
		for(i=1;i<=n;i++)d[i]=((s[i]-t[i]+10)%10-(s[i-1]-t[i-1]+10)%10+10)%10;
		sort(d+1,d+n+1);
		if(d[n]==0){
			puts("0");
			continue;
		}
		sum[n+1]=0;
		for(i=n;i>0;i--)sum[i]=sum[i+1]+10-d[i];
		ts=0;
		for(i=1;i<n;i++){
			ts+=d[i];
			if(ts==sum[i+1]){
				printf("%d\n",ts);
				break;
			}
		}
	}
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/8974427.html