CF720E Cipher 题解

CF720E Cipher 题解


知识点

进制,模拟,贪心。

分析

发现我们想要确定一位数时,只有两种方法:

  1. 该位数字自己加 \(1\),从变化顺序可以看出它是哪一位。
  2. 该位数字加 \(1\),导致高位数字出现变化,看出它现在变成了 \(0\)。这种情况包括整个数字达到了 \(n+1\) 位的情况。

那么我们从高位开始遍历,记一个答案为 \(ans\),最小进位且变化的值为 \(len\),初始时设为 \(1\)

每次想要确定这一位数是否可行,就要和别的数进行比较,直到能够把两个数区分开。假设此位为 \(c\),比较的为 \(j\),那么比较的方法有两种:

  1. 循环串最长公共前缀长度 \(+1\)
  2. 如果 \(j\) 能够引起高位进位,且进位能够看出来。

我们对于同一个 \(j\),在这两种中取 \(\min\),得到这一位的答案 \(lim\),最后再整个答案 \(ans\) 中取 \(\max\)

当我们从高一位到低一位的时候,我们需要更新 \(ans,len\),不过根据定义,也不难实现。

时间复杂度 \(O(nw^2),w=10\)

代码

constexpr int N(18+10);

char s[N],t[N];
int Cas,n;
ll ans,len;

int Cmain() {
	/*DE("Input");*/
	I(n),scanf("%s",s),ans=0,len=1;
	/*DE("Solve");*/
	FOR(i,0,n-1) {
		const int c(s[i]^48);
		scanf("%s",t),ans=ans*10-c;
		FOR(j,0,9)if(j!=c) {
			ll lim(len*10-max(j,c)); //上一位进位带来的影响
			FOR(k,0,min(lim-1,9ll))if(t[(c+k)%10]!=t[(j+k)%10]&&(lim=k,true))break;
			tomax(ans,lim);
		}
		len=len*10-c;
		FOR(j,1,9)if(t[c]!=t[(c+j)%10]&&(tomin(len,(ll)j),true))break;
	}
	/*DE("Output");*/
	O(ans,'\n');
	return 0;
}

signed main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	for(I(Cas); Cas; --Cas)Cmain();
	return 0;
}

posted @ 2025-09-03 19:33  Add_Catalyst  阅读(10)  评论(0)    收藏  举报