一本通提高篇—哈希

#10034. 「一本通 2.1 例 2」图书管理

在这里插入图片描述
代码

#include "stdio.h"
#include "string.h"
const int mod1 = 1e6 + 3, mod2 = 1e6 + 9, p1 = 47, p2 = 79, N = 30009;
int book[N], a[mod2 + 8], b[mod2 + 8];
int shu = 0;
void lianbiao(int x, int y) {
    
    
    book[++shu] = a[x]; //book[++shu]=a[x]上一个标记值
    a[x] = shu;
    b[shu] = y; //有且只有一个(很重要)
}
int find(int x, int y) {
    
    
    for (int i = a[x]; i != 0 ; i = book[i]) {
    
    
        if (b[i] == y)
            return 1;
    }

    return 0;
}
int main() {
    
    
    int n, i, j;
    scanf("%d", &n);
    char c[10], cc[1000];

    while (n--) {
    
    
        scanf("%s", c);
        gets(cc);
        int x = 0, y = 0;

        for (i = 0; i < strlen(cc); i++) {
    
     
        //x,y双哈希思想,两关键字决定一个字符,减小误差
            x = (x * p1 + cc[i]) % mod1;
            y = (y * p2 + cc[i]) % mod2;
        }

        if (c[0] == 'a')
            lianbiao(x, y);
        else {
    
    
            if (find(x, y))
                printf("yes\n");
            else
                printf("no\n");
        }
    }
}

#10035. 「一本通 2.1 练习 1」Power Strings

在这里插入图片描述
代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[1000005];
int nxt[1000005],l;
void getnext()
{
    
    
    int k=-1,j=0;
    nxt[0]=-1;
    while(j<l)
	{
    
    
        if(k==-1||s[k]==s[j])
		{
    
    
            k++;j++;
            nxt[j]=k;
        }
        else 
			k=nxt[k];
    }
}
int main()
{
    
    
    while(~scanf("%s",s))
	{
    
    
        if(s[0]=='.') 
			break;
        l=strlen(s);
        getnext();
        if(l%(l-nxt[l]))
        	printf("1\n");
        else
        	printf("%d\n",l/(l-nxt[l]));
    }
    return 0;
}

#10036. 「一本通 2.1 练习 2」Seek the Name, Seek the Fame

没写

#2823. 「BalticOI 2014 Day 1」三个朋友

在这里插入图片描述
代码

#include "stdio.h"
#include "algorithm"
#include "string.h"
#include "math.h"
using namespace std;
#define ull unsigned long long
char c[2000009];
ull a[2000009],b[2000009];
int main()
{
    
    
	ull l,t=0,s,sum;
	scanf("%llu%s",&l,c+1);
	if(l%2==0)
	{
    
    
		printf("NOT POSSIBLE\n");
		return 0;
	}
	b[0]=1;//131好像是根据字符对应的最大数字对比得到的
	for(int i=1; i<=l; i++)
	{
    
    
		a[i]=a[i-1]*131+c[i];
		b[i]=b[i-1]*131; //注意:b[1]=131,为什么b[1]不是1而是131,值得思考
	}
	for(int i=1; i<=l; i++)
	{
    
    
		ull k,j;//k记录前半段,j记录后半段
		if(i<=l/2+1)//前半段加了字符,第i个就是加入的字符
			k=a[l/2+1]-a[i]*b[l/2+1-i]+a[i-1]*b[l/2+1-i];
//      第二个a是插入的:aabbaa
//  ->  aabbaa-aa*131*131*131*1=bbaa
//  ->  bbaa+a*131*131*131*1=abbaa
		else
			k=a[l/2];
		if(i<=l/2+1)//i<l/2+i都可以看个人喜好
			j=a[l]-a[l/2+1]*b[l/2];
		else
			j=a[l]-a[i]*b[l-i]+(a[i-1]-a[l/2]*b[i-1-l/2])*b[l-i];
		if(k==j)
		{
    
    
			if(t&&sum!=k)//注意:aaaaa如果没有sum,则会输出NOT UNIQUE 
			{
    
    
				printf("NOT UNIQUE\n");
				return 0;
			}
			t=1,s=i,sum=k;
		}
	}
	if(!t)
	{
    
    
		printf("NOT POSSIBLE\n");
		return 0;
	}
	if(s<=l/2+1)
		printf("%s",c+l/2+2);
	else
	{
    
    
		for(int i=1; i<=l/2; i++)
			printf("%c",c[i]);
	}
}

#10041. 「一本通 2.1 练习 7」门票

在这里插入图片描述
代码

//1ll是为了在计算时,
//把int类型的变量
//转化为long long
//单哈希做法很好想,但是冲突概率极大以至于无法通过此题,
//所以考虑使用双哈希。
//双哈希一般是不会被卡掉的,直接认为是正确的就好了
#include "stdio.h"
#include "algorithm"
#include "string.h"
const int  N=1e6,p1=249439,p2=249449;//1e6+7 和 1e6+9超内存 
//414971和 414977是质数 
int vis1[p1];
int vis2[p2];//双哈希
int main()
{
    
    
	int s1=1;
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	vis1[1]=vis2[1]=1;//a0=0;
	for(int i=1; i<=N; i++)
	{
    
    
		s1=(1ll*a*s1+s1%b)%c;
		int m1=s1%p1;
		int m2=s1%p2;
	//	printf("%d %d %d\n",s1,m1,m2);
		if(vis1[m1]&&vis1[m1]==vis2[m2])
		{
    
    
			printf("%d\n",i);
			return 0;
		}
		if(!vis1[m1])	vis1[m1]=i;
		if(!vis2[m2])	vis2[m2]=i;
	}
	printf("-1\n");
}

#10042. 「一本通 2.1 练习 8」收集雪花

在这里插入图片描述
代码

#include "stdio.h"
#include "algorithm"
#include "iostream"
#include "map"
using namespace std;
int a[1000006];
map<int,int>mp;
int main()
{
    
    
	int n,m,l=1;
	int len=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
    
    
		cin>>a[i];
		if(mp.count(a[i]))//a[i]出现的次数或写成mp.find(a[i])!=mp.end() 
		{
    
    
			while(a[l]!=a[i])
			{
    
    
				mp.erase(mp.find(a[l]));//删a[l] 
				l++;
			}	
			l++; 
		 } 
		 else
		 	mp[a[i]]=1;
		len=max(len,i-l+1); 
	}
	cout<<len<<endl;
}

#10043. 「一本通 2.2 例 1」剪花布条

在这里插入图片描述
代码

#include "stdio.h"
#include "string.h"
char a[1009],c[1009];
int b[1009];
int main()
{
    
    
	while(~scanf("%s",a))
	{
    
    
		memset(b,0,sizeof(b));
		int l1=strlen(a);
		if(l1==1&&a[0]=='#')
			break;
		scanf("%s",c);
		int l2=strlen(c);
		int i,j;
		for(i=0; i<l2; i++)
		{
    
    
			j=i;
			while(j!=0)
			{
    
    
				j=b[j];
				if(c[i]==c[j])
				{
    
    
					b[i+1]=j+1;
					break;
				}

			}
		}
		j=0;
		int s=0;
		for(i=0; i<l1; i++)
		{
    
    
			while(a[i]!=c[j]&&j)//while要在if上面,while过后进行if 
				j=b[j];
			if(a[i]==c[j])
			{
    
    
				j++;
				if(j==l2)
				{
    
    
					s++;
					j=0;
				}
				continue;
			}
		}
		printf("%d\n",s);
	}
}

#10035. 「一本通 2.1 练习 1」Power Strings

在这里插入图片描述
代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[1000005];
int nxt[1000005],l;
void getnext()
{
    
    
    int k=-1,j=0;
    nxt[0]=-1;
    while(j<l)
	{
    
    
        if(k==-1||s[k]==s[j])
		{
    
    
            k++;j++;
            nxt[j]=k;
        }
        else 
			k=nxt[k];
    }
}
int main()
{
    
    
    while(~scanf("%s",s))
	{
    
    
        if(s[0]=='.') 
			break;
        l=strlen(s);
        getnext();
        if(l%(l-nxt[l]))
        	printf("1\n");
        else
        	printf("%d\n",l/(l-nxt[l]));
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_53623850/article/details/121301804