Distinct Substrings(2019年湖南acm第三题)

这篇博客介绍了如何利用逆序字符串和exKMP算法来解决一个数学问题:给定一串数字,在其后添加数字x,计算3x*h[x]%mod的异或和。通过计算每个数字x增加的子串数量,并排除重复子串,最终得出异或结果。代码中展示了如何实现这一算法,包括z_function函数的使用和异或操作的细节。
摘要由CSDN通过智能技术生成

题目的意思是:给一串数字,然后在后面添加一个数字x问你新增了多少子串h[x],求这个数字x取从1到m时 3x*h[x]%mod的异或和。

思路:考虑新添加一个数字,增加的子串的数量为所有以该数字结尾的后缀,但是会出现前面已经出现过的子串,所以我们需要算出在没有添加之前出现过多少以该数字结尾的字符串,考虑将这些数反过来,然后用exkmp求出,next[i]: T[i~n-1]和T的最长公共前缀;对于1~m的每一个数字,我们只要求出其最大值即可,然后n-最大值就是这个数字的答案,将所有的答案异或就是最后的答案了。

 代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int mx[N];
typedef long long ll;
const ll mod=1e9+7;
int a[N];
int s[N];
void z_function(int s[],int n){
	for(int i=1,l=0,r=0;i<n;++i){
		if(i<=r&&a[i-l]<r-i+1){
			a[i]=a[i-l];
		}else{
			a[i]=max(0,r-i+1);
			while(i+a[i]<n&&s[a[i]]==s[i+a[i]]) ++a[i];
		}
		if(i+a[i]-1>r) l=i,r=i+a[i]-1;
	}
}
int n,m;
int main(){
	while(~scanf("%d%d",&n,&m)){
		int maxx=0;
		for(int i=0;i<n;++i){
			scanf("%d",&s[i]);
			maxx=max(maxx,s[i]);
			a[i]=0;
		}
		for(int i=0;i<=m;++i){
			mx[i]=0;
		}
		reverse(s,s+n);
		z_function(s,n);
		for(int i=0;i<n-1;++i){
			mx[s[i]]=max(mx[s[i]],1+a[i+1]);
		}
		mx[s[n-1]]=max(mx[s[n-1]],1);
		ll ans=0;
		ll jc=1;
		for(int i=1;i<=m;++i){
			jc=jc*3%mod;
			if(mx[i]==0){
				ans^=((n+1)*jc%mod);
			}
			else{
				ans^=(((n+1)-mx[i])*jc%mod);
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值