题目大意:给你n个仅由0~9组成的字符串作为密码(1 ≤ N ≤ 100,000),每个字符串长度<=5,两个字符串A,B如果长度相同且对于每个位置i ,|A[i] - B[i]|(注意绝对值)都相同,那么这两个字符串就是等价的,问你至多多少次 能找到正确密码。简单说就是n个字符串有多少种?
分析:如果暴力匹配,最坏的情况是O(1e5*1e5),绝对超时!找其他方法吧,每个密码的长度只有五个,我们可以在长度上考虑。如果把每个密码串转化为数字,最大的情况也就是 99999,我们再用标记数组,这样每次查询就能达到O(1)的复杂度,计算数字也只是循环五次,时间复杂度可以降到O(5*le5),1s之内就能过。对于绝对值的情况,我们可以用DFS进行处理,如果当前的已经找到,就不用进行处理了,否则像第二个样例的情况就会出错。我们只处理没有被标记过的情况。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int ma=1e6+10;
bool vis[5][ma];
void dfs(char s[],int pos,int len,int d)
{
if(pos==len)
{
int t=0;
for(int i=0;i<len;++i)
{
t*=10;
t+=s[i]-'0';
}
vis[len-1][t]=true;
return;
}
s[pos]-=d;
if(s[pos]>='0') dfs(s,pos+1,len,d);
s[pos]+=2*d;
if(s[pos]<='9') dfs(s,pos+1,len,d);
s[pos]-=d;
}
int main()
{
int t,cas=1,n;
scanf("%d",&t);
char s[6];
while(t--){
memset(vis,false,sizeof(vis));
scanf("%d",&n);
int ans=0;
for(int i=0;i<n;++i)
{
scanf("%s",s);
int len=strlen(s),t=0;
for(int j=0;j<len;++j)
{
int d=s[j]-'0';
t*=10;
t+=d;
}
if(vis[len-1][t]) continue;
ans++;
vis[len-1][t]=true;
for(int j=1;j<=9;++j)
dfs(s,0,len,j);
}
printf("Case %d: %d\n",cas++,ans);
}
return 0;
}