【真题-字符串转数字的处理】密文搜索

首先我想在这里吐槽一下,还有三天左右比赛,自己竟然状态出现了点问题...拿到真题就觉得心塞然后莫名其妙地浮躁。

必须调整状态!!!!!明天要开始复习笔记了,希望不负己望!


大致思路

方法很巧妙,我刚开始想到的就是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;    
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值