昨天整了kmp和hash,今天刷题来了,但过程十分艰难,看明白跟敲出来不是一个量级。
先来一道hash模板试试手 ,先是狠捞的冒泡排序,然后编了个很简单的hash函数,让字符串每一位转int型,完事分别乘不同的数,完事相加,最后取模,然后遍历看看有几个不一样的
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
long long int n,a[10005],max=212370440130137957ll;
char s[10005];
long long int hash();
int main()
{
scanf("%lld",&n);
long long int i;
for(i=0;i<n;i++)
{
scanf("%s",s);
a[i]=hash();
}
long long int j,t;
for(j=0;j<n-1;j++)
{
for(i=0;i<n-1-j;i++)
{
if(a[i]>a[i+1])
{
t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
}
}
long long int sum=1;
for(i=0;i<n-1;i++)
{
if(a[i]!=a[i+1])
sum++;
}
printf("%lld",sum);
return 0;
}
long long int hash()
{
long long int len;
len=strlen(s);
long long int i,ss=1,k;
for(i=0;i<len;i++)
{
k=(int)s[i];
ss=ss*(i+1)*k%max;
}
return ss;
}
接下来这题实在hash模板题后面,结果我一看,这不正好能直接用kmp做吗,完事直接kmp过了。就俩字符串咱给他拼成两个长串,然后去求kmp里的next数组,看看最长的前后缀是多长。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int main()
{
int a[10000],b[10000];
char s1[10000],s2[10000];
scanf("%s %s",s1,s2);
int la=strlen(s1),lb=strlen(s2);
int i;
char s3[10000],s4[10000];
for(i=0;i<la;i++)
{
s3[i]=s1[i];
s4[i+lb]=s1[i];
}
for(i=0;i<lb;i++)
{
s3[i+la]=s2[i];
s4[i]=s2[i];
}
int j=-1,sum=0;
a[0]=-1;
b[0]=-1;
while(i<la+lb)
{
if(j==-1||s3[i]==s3[j])
{
i++;j++;
a[i]=j;
if(a[i]>sum)sum=a[i];
}
else
{
j=a[j];
}
}
j=-1;
i=0;
while(i<la+lb)
{
if(j==-1||s4[i]==s4[j])
{
i++;j++;
b[i]=j;
if(b[i]>sum)sum=b[i];
}
else
{
j=b[j];
}
}
printf("%d",sum);
return 0;
}
字典树,自己想的法子超时了,还是得字典树
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int n,m;
struct st
{
char name[100];
int ha;
}na[20000];
char he[55];
void fast(int left,int right);
int find(int l,int r);
int main()
{
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
scanf("%s",na[i].name);
na[i].ha=0;
}
scanf("%d",&m);
fast(1,n);
for(i=0;i<m;i++)
{
scanf("%s",he);
int ff;
ff=find(1,n);
if(ff==-1)
printf("WRONG\n");
else if(na[ff].ha>0)
{
printf("REPEAT\n");
}
else if(na[ff].ha==0)
{
printf("OK\n");
na[ff].ha=1;
}
}
return 0;
}
void fast(int left,int right)
{
int l=left,j=right,k;
char t[100],m[100];
strcpy(m,na[left].name);
if(l>j)
return ;
while(l<j)
{
while(l<j&&(strcmp(na[j].name,m))>=0)j--;
while(l<j&&(strcmp(na[l].name,m))<=0)l++;
if(l<j)
{
strcpy(t,na[l].name);
strcpy(na[l].name,na[j].name);
strcpy(na[j].name,t);
}
}
strcpy(na[left].name,na[l].name);
strcpy(na[l].name,m);
fast(left,l-1);
fast(l+1,right);
}
int find(int l,int r)
{
int mid=l+(r-1)/2;
if(strcmp(na[mid].name,he)==0)return mid;
if(l>r)return -1;
else if(strcmp(na[mid].name,he)>0)return find(l,mid-1);
else return find(mid+1,r);
}
//超时我淦
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int tree[500001][50];
int ff[500001];
int kk=0;
char s[100];
int n,m;
void goin();
int find();
int main()
{
scanf("%d",&n);
int i;
for(i=0;i<n;i++)
{
scanf("%s",s);
goin();
}
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%s",s);
int f=find();
if(f==1)
printf("OK\n");
else if(f>1)
printf("REPEAT\n");
else printf("WRONG\n");
}
return 0;
}
void goin()
{
int k=0,x,len=strlen(s);
for(x=0;x<len;x++)
{
int p;
p=s[x]-'a';
if(tree[k][p]==0)
{
tree[k][p]=++kk;
}
k=tree[k][p];
}
ff[k]=1;
}
int find()
{
int z=0;
int le=strlen(s);
int o;
for(o=0;o<le;o++)
{
int y=s[o]-'a';
if(tree[z][y]==0)
{
return 0;
}
z=tree[z][y];
}
if(ff[z]==2||ff[z]==0)return ff[z];
ff[z]=2;
return 1;
}
还是得字典树淦
这题看着简单,做着。。。就硬超时,样例给十万个1和2,传统快排直接快不起来了。重复的数字确实是难搞。只能是整优化的快排了。至于做法,像传统快排那样搞左右指针,一路给他减过去完事,但右指针得弄俩,不然不好办。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
long long n,c,a[300000];
void fast(int l,int r);
int main()
{
scanf("%lld %lld",&n,&c);
long long int i;
for(i=0;i<n;i++){
scanf("%lld",&a[i]);}
fast(0,n-1);
long long int r=0,k=0,l=0,sum=0;
for(l=0;l<n;l++)
{
while(r<n&&a[r]-a[l]<=c)r++;
while(k<n&&a[k]-a[l]<c)k++;
sum=sum+r-k;
}
printf("%lld",sum);
return 0;
}
void fast(int l,int r)
{
long long int mid=a[(l+r)/2],t;
int i=l,j=r;
do{
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j)
{
t=a[i];
a[i]=a[j];
a[j]=t;
i++;
j--;
}
}while(i<=j);
if(l<j) fast(l,j);
if(i<r) fast(i,r);
}