Codeforces Tutorial
C. Promocodes with Mistakes
Problem Analysis
题意:有n
个长度均为6
的校验码,要求最大的容错率k
,使得对于任意一个校验码都可以判定其在不超过k个错误下为这n个校验码中的哪一个 。
之前没遇到过这种类型,学习了。
我们可以采用逆向思维来思考这个问题。
两个字符串的差异:
\[ strdif(s_1,s_2)=\sum_{k=0}^5 s_1[k]!=s_2[k] \]
对于任意的两个\(s_i\)和\(s_j\),假设存在一个字符串 \(s_k\),和一个不合法的\(k\),使得
\[ strdif(s_i,s_k) \leq k \land strdif(s_j,s_k) \leq k \]
\[ strdif(s_i,s_j) \leq strdif(s_i,s_k)+strdif(s_j,s_k) \leq 2k \]
所以:
不合法的
\[ k \ge \frac{strdif(s_i,s_j)+1}{2} \]
那么合法的
\[ k \leq \frac{strdif(s_i,s_j)-1}{2} ,for \quad i,j \in \left[1,n\right] \land i \neq j \]
Acepted Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cmath>
#include<map>
#include<istream>
#include<cassert>
#include<set>
#define DEBUG(x) cout<<#x<<" = "<<x<<endl
#define DEBUG2(x,y) cout<<#x<<" = "<<x<<" , "\
<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
int n;
char promocode[1100][10];
int strdif(char a[],char b[])
{
int cnt=0;
for(int ii=0;ii<6 ;ii++ ){
if(a[ii]!=b[ii])cnt++;
}
return cnt;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d\n",&n);
for(int ii=1;ii<=n ;ii++ ){
scanf("%s",promocode[ii]);
}
int ans=6;
for(int ii=1;ii<=n-1 ;ii++ ){
for(int jj=ii+1;jj<=n ;jj++ ){
ans=min(ans,(strdif(promocode[ii],promocode[jj])-1)/2);
}
}
printf("%d\n",ans);
}
Wrong Answer Cases
Test 3
What I Learn
这种解法实际上要求构造一个不合法的输入,根据这个不合法的输入,推断出\(k\)的要求。
核心就是\(k\)和不合法的输入是关联的。