字符串算法

int128

高精度本质上是字符串实现的,所以把\(int128\)放这了。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned __int128 LLL;
LLL read() {
    LLL x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
void out(LLL x) {
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) out(x / 10);
    putchar(x % 10 + '0');
}
int main() {
    LLL a, b;
    a = read(), b = read();
    out(a + b);
    return 0;
}

字典树

不会!!!

HASH

质数:1e9+7,

212370440130137957ll 。

双模

#include<bits/stdc++.h>
using namespace std;
const unsigned long long base=233,mod1=1e9+7,mod2=212370440130137957ll;
struct node{
	unsigned long long x,y;
}a[10100];
bool cmp(node t1,node t2){
	return t1.x<t2.x;
}
unsigned long long cnt=1,n,ans1,ans2;string s;
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		ans1=0;
		ans2=0;
		cin>>s;
		for(int j=0;j<s.size();j++){
			ans1=(ans1*base+s[j])%mod1;
			ans2=(ans2*base+s[j])%mod2;
		}
		a[i].x=ans1;
		a[i].y=ans2;
	} 
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<n;i++)
		if(a[i].x!=a[i+1].x || a[i].y!=a[i+1].y)cnt++;
	printf("%llu",cnt);
	return 0;
}

hash提取子串

int get(l,r){
	return (hsh[r]-hsh[l-1]*pw[r-l+1]%mod+mod)%mod;
}
pw[0]=1;
for(int i=1;i<=n;i++){
	pw[i]=pw[i-1]*base%mod;
	hsh[i]=(hsh[i-1]*base+y[i])%mod;
}

hash表的应用

我们知道,对于一些很大很大的值,我们不能开数组(会G),这时候,某个笨蛋会开map映射,但是map他带个log,所以我们可以用hash。具体原理是:

val(原本的值)%mod=sm(映射后的值),rcd[sm]=val

然后有时候这个值会冲突,那么一直向后走就好了(走到底再拐回来)。


当然这是幼儿园小盆友用的方法了。
一种可能更优的方法(from @jiangchenyangsong)是用链式前向星,对每个取余后的值建链(重复的时候建)。
如下是两个hash表:

int head_bk[M],last_bk[M],tot_bk,rcd_bk[M];bool bk_bk[M];
int hash_bk(int val){
	int u=val%mod;
	for(int i=head_bk[u];i;i=last_bk[i])
		if(rcd_bk[i]==val)return bk_bk[i];
	last_bk[++tot_bk]=head_bk[u],head_bk[u]=tot_bk,rcd_bk[tot_bk]=val;return 0;
}
void hash_bk_set(int val){
	int u=val%mod;
	for(int i=head_bk[u];i;i=last_bk[i])
		if(rcd_bk[i]==val){bk_bk[i]=1;return;}
	last_bk[++tot_bk]=head_bk[u],head_bk[u]=tot_bk,rcd_bk[tot_bk]=val;bk_bk[tot_bk]=1;return;
}

int head_jmp[M],last_jmp[M],tot_jmp,rcd_jmp[M],save_jmp[M];
int hash_jmp(int val){
	int u=val%mod;
	for(int i=head_jmp[u];i;i=last_jmp[i])
		if(rcd_jmp[i]==val)return save_jmp[i];
	last_jmp[++tot_jmp]=head_jmp[u],head_jmp[u]=tot_jmp,rcd_jmp[tot_jmp]=val;return 0;
}
void hash_jmp_set(int val,int opt){
	int u=val%mod;
	for(int i=head_jmp[u];i;i=last_jmp[i])
		if(rcd_jmp[i]==val){save_jmp[i]=opt;return;}
	last_jmp[++tot_jmp]=head_jmp[u],head_jmp[u]=tot_jmp,rcd_jmp[tot_jmp]=val;save_jmp[tot_jmp]=opt;return;
}

最后推荐两个来自未来ZJ省队的模数:\(\text{1e6+33}\)\(\text{65536+1}\)

KMP

利用最大前后缀长度进行匹配

\(O(n+m)\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+110;
char s1[N],s2[N];
int la,lb,border[N],j;
int main(){
	cin>>s1+1>>s2+1;
	la=strlen(s1+1);
	lb=strlen(s2+1);
	for(int i=2;i<=lb;i++){
		while(j>0 && s2[j+1]!=s2[i])j=border[j];
		if(s2[j+1]==s2[i])j++;
		border[i]=j;
	}
	j=0;
	for(int i=1;i<=la;i++){
		while(j>0 && s2[j+1]!=s1[i])j=border[j];
		if(s2[j+1]==s1[i])j++;
		if(j==lb){
			printf("%d\n",i-lb+1);
			j=border[j];
		}
	}
	for(int i=1;i<=lb;i++)printf("%d ",border[i]);
	return 0;
}

高精度乘法

#include<bits/stdc++.h>
using namespace std;
const int N=4010;
struct node{
	int len,num[N];
};
node operator * (node A,node B){
	node C;C.len=A.len+B.len-1;
	for(int i=1;i<=B.len;i++)
		for(int j=1;j<=A.len;j++)
			C.num[j+i-1]+=A.num[j]*B.num[i];
	for(int i=1;i<=C.len;i++){
		C.num[i+1]+=C.num[i]/10;
		C.num[i]%=10;
	}
	while(C.num[C.len+1]){
		C.len++;
		C.num[C.len+1]+=C.num[C.len]/10;
		C.num[C.len]%=10;
	}
	while(C.num[C.len]==0 && C.len>1)
		C.len--;//防止你输出"000"
	return C;
}
char sc[N];
void write(node A){
	for(int i=A.len;i>=1;i--)printf("%d",A.num[i]);
	return;
}
int main(){
	node A,B;
	scanf("%s",sc+1);
	A.len=strlen(sc+1);
	for(int i=1;i<=A.len;i++)A.num[i]=sc[A.len-i+1]-'0';
	scanf("%s",sc+1);
	B.len=strlen(sc+1);
	for(int i=1;i<=B.len;i++)B.num[i]=sc[B.len-i+1]-'0';
	write(A*B);
	return 0;
}

SA

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+110;

char s[N];
int n,m,sa[N],rk[N<<1],oldrk[N<<1],id[N],cnt[N];
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	m=max(n,300);
	for(int i=1;i<=n;i++)cnt[rk[i]=s[i]]++;
	for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
	for(int i=n;i>=1;i--)sa[cnt[rk[i]]--]=i;
	
	for(int w=1;w<n;w<<=1){
		memset(cnt,0,sizeof(cnt));
		memcpy(id,sa,sizeof(sa));
		for(int i=1;i<=n;i++)cnt[rk[id[i]+w]]++;
		for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
		for(int i=n;i>=1;i--)sa[cnt[rk[id[i]+w]]--]=id[i];
		memset(cnt,0,sizeof(cnt));
		memcpy(id,sa,sizeof(sa));
		for(int i=1;i<=n;i++)cnt[rk[id[i]]]++;
		for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
		for(int i=n;i>=1;i--)sa[cnt[rk[id[i]]]--]=id[i];
		memcpy(oldrk,rk,sizeof(oldrk));
		for(int p=0,i=1;i<=n;i++){
			if(oldrk[sa[i]]==oldrk[sa[i-1]] && oldrk[sa[i]+w]==oldrk[sa[i-1]+w])rk[sa[i]]=p;
			else rk[sa[i]]=++p;
		}
	}
	for(int i=1;i<=n;i++)printf("%d ",sa[i]);
	printf("\n");
	printf("\n");
	printf("\n");
	return 0;
} 
posted @ 2023-03-19 13:35  FJOI  阅读(22)  评论(0)    收藏  举报