今年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; } } } }