P8630
[蓝桥杯 2015 国 B] 密文搜索
题目描述
福尔摩斯从 X 星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为 \(8\) 的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。
请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。
输入格式
输入第一行:一个字符串 \(s\),全部由小写字母组成,长度小于 \(1024 \times 1024\)。
紧接着一行是一个整数 \(n,\) 表示以下有 \(n\) 行密码,\(1 \le n \le 1000\)。
紧接着是 \(n\) 行字符串,都是小写字母组成,长度都为 \(8\)。
输出格式
一个整数,表示每行密码的所有排列在 \(s\) 中匹配次数的总和。
样例 #1
样例输入 #1
aaaabbbbaabbcccc
2
aaaabbbb
abcabccc
样例输出 #1
4
提示
第一个密码匹配了 \(3\) 次,第二个密码匹配了 \(1\) 次,一共 \(4\) 次。
挺好的一道题 更新了很多以前不知道的技巧
最朴素的方法是next_permutation 但是好像会WA3个点?
最好的方法是截取初始中的每个连续8位 sort后map[s]++
再输入n个s时对每个s sort ans+=map[s] 即可
这里sort特别巧妙 因为是全排列所以说只要sort后相同就+1
注意 字符串内部sort格式:sort(s.begin(),s.end())
Code
#include<bits/stdc++.h>
using namespace std;
string ss,s;
int n,cnt;
map<string,int>cs;
int main()
{
ios::sync_with_stdio(false);
cin>>s;
int len=s.size();
for(int i=0;i+7<len;i++)
{
string a="";
a+=s[i];a+=s[i+1],a+=s[i+2],a+=s[i+3],a+=s[i+4],a+=s[i+5],a+=s[i+6],a+=s[i+7];
sort(a.begin(),a.end());
// cout<<a<<"\n";
cs[a]++;
}
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s;
sort(s.begin(),s.end());
cnt+=cs[s];
}
cout<<cnt<<"\n";
return 0;
}
好像next_permutation也能过 只是还是要用map
引以为戒!
WA版本:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s,ss;int n,cnt;
set<string>st;
int main()
{
cin>>ss;
scanf("%d",&n);
while(n--)
{
cin>>s;
sort(s.begin(),s.end());
do{
if(!st.count(s))
{
st.insert(s);int idx=0,tot=0;
while((idx=ss.find(s,idx))!=string::npos)
{
idx++;
tot++;
}
cnt+=tot;
}
}while(next_permutation(s.begin(),s.end()));
}
cout<<cnt<<"\n";
return 0;
}
AC版本:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
string s,ss;int n,cnt;
map<string,int>cs;
signed main()
{
cin>>ss;
scanf("%d",&n);
while(n--)
{
cin>>s;
sort(s.begin(),s.end());
do{
cs[s]++;
}while(next_permutation(s.begin(),s.end()));
}
int len=ss.size();
for(int i=0;i<len-7;i++)
cnt+=cs[ss.substr(i,8)];
cout<<cnt<<"\n";
return 0;
}
此生无悔入OI 来生AK IOI

浙公网安备 33010602011771号