首先我想在这里吐槽一下,还有三天左右比赛,自己竟然状态出现了点问题...拿到真题就觉得心塞然后莫名其妙地浮躁。
必须调整状态!!!!!明天要开始复习笔记了,希望不负己望!
大致思路:
方法很巧妙,我刚开始想到的就是KMP算法去匹配字符串的裸题,但是发现还有个“全排列”的条件,如果n很多的话,我全排列的答案就很多了还得一个个去匹配,感觉就容易TLE。
然而,这里的方法很奇妙:把字符串转化成数字——一个字符串当作26进制的数字,而且先把字符串的字母从小到大排列之后再来转,大家都这样,其实可以变相完成“无序匹配”:
ll zhuan(char ss[])//把长度为8的26进制字符串转化为10进制数
{
ll ans=0;
char s1[12];
memcpy(s1,ss,9);
sort(s1,s1+8);//注意排序 //如果都从小到大排序了再来匹配,则相当于“全排列”
for(int i=0;i<8;i++)
ans = ans*26 + (s1[i]-'a'); //转化为26进制数!!!
return ans;
}
对于原序列,每8个字做一个区间都转成一个26进制数放到数组里。最后就去遍历这个数组,相当于每个8个字的区间里去看看有没有和n个密码的其中一个相等的(二分查找!嘿嘿,我就用我自己的二分法写法,也行)。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
char str[1024*1025],s[12];
ll a[1024*1025];//存每个区间的串的10进制形式
ll cont[1100];//存每个串的10进制形式
int n;
ll zhuan(char ss[])//把长度为8的26进制字符串转化为10进制数
{
ll ans=0;
char s1[12];
memcpy(s1,ss,9);
sort(s1,s1+8);//注意排序
for(int i=0;i<8;i++)
ans = ans*26 + (s1[i]-'a');
return ans;
}
void find(ll c[],int l,int r,ll num,int &cnt)
{
/* if(l==r){
cnt += c[l]==num;
return;
}
int mid=(l+r)/2;
if(c[mid]>=num)
find(c,l,mid,num,cnt);
if(c[mid+1]<=num)
find(c,mid+1,r,num,cnt); */
while(l<r)
{
int mid=(l+r)/2;
if(c[mid]==num)
{
cnt++;
return;
}
if(c[mid]>num)
{
r=mid;
}
else if(c[mid]<num)
{
l=mid+1;
}
}
}
int main()
{
scanf("%s%d",str,&n);
for(int i=0;str[i+7];i++)
{
a[i]=zhuan(str+i);
printf("a:%lld\n",a[i]);
}
for(int k=0;k<n;k++)
{
scanf("%s",s);
sort(s,s+8);
cont[k]=zhuan(s);
printf("count: %lld\n",cont[k]);
}
sort(cont,cont+n);
ll ans=0;
for(int i=0;str[i+7];i++)//对每个区间找相等的(二分查找)
{
int cnt=0;
find(cont,0,n,a[i],cnt);//在cont中找a[i]的个数
ans+=cnt;
}
printf("%lld\n",ans);
return 0;
}