[CF1598G]The Sum of Good Numbers

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1598G]The Sum of Good Numbers相关的知识,希望对你有一定的参考价值。

The Sum of Good Number

题解

这种高精加法哈希比较的题真的很臭呀,赛后一群人在那里卡模数,真的吐了

我们考虑如何快速比较两个大整数的和,显然,哈希是一种很好的方法,所以我们可以将比较两个很长的大整数的和转换成比较它们哈希值的和。
由于我们所有的数都是 “好数” ,也就是不含 0 0 0 的数,所以它的进位一定是比较少的,其进位最多只会比做加法的两个数多出 1 1 1 位。
所以我们加的两个数要么是长度几乎相当,都是 ∣ x ∣ |x| x ∣ x ∣ − 1 |x|-1 x1,要么较长的为 ∣ x ∣ |x| x,其前缀的大部分都与我们目标的 x x x相同。

对于前面的都是 ∣ x ∣ |x| x ∣ x ∣ − 1 |x|-1 x1 的情况,我们可以特殊记录一下,从每个点开始的长度为 ∣ x ∣ |x| x或者 ∣ x ∣ − 1 |x|-1 x1 的前缀的哈希值,将相邻的两个加起来,判断它的哈希值是否等于我们目标 x x x的哈希值。
对于第二种情况,我们可以猜测大部分情况下与前缀大部分与我们目标 x x x相同的数是比较少,对于每个这样的前缀就暴力枚举其往前扩散与往后扩散的哈希值,看是否存在一个使得加起来可以达到我们目标的 x x x

由于赛后一群人在那里卡哈希,把笔者都给卡*了,所以笔者用的是随机的哈希数,也就是先列出一大堆哈希数,每次从里面随机出两个作为这次的哈希模数。

也许常数会有点大。
时间复杂度 O ( ∣ s ∣ + ∣ x ∣ ) O\\left(|s|+|x|\\right) O(s+x)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define MAXM (1<<20)+5
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;     
const int INF=0x3f3f3f3f;  
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){putchar('\\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int lens,lenx,mod1,mod2;pii nowx,sum1[MAXN],sum2[MAXN];
int mp[15]={100001651,100001623,100001611,100001591,100001581,100001569,100001537,100001533,100001507,100001467};
char str[MAXN],x[MAXN];
pii operator + (pii x,pii y){return mkpr(add(x.fir,y.fir,mod1),add(x.sec,y.sec,mod2));}
bool operator == (pii x,pii y){return x.fir==y.fir&&x.sec==y.sec;}
signed main(){
	scanf("%s\\n%s",str+1,x+1);
	mt19937 e(time(0));uniform_int_distribution<int> g(0,9);
	int u=g(e),v=g(e);mod1=mp[u];mod2=mp[v];
	lens=(int)strlen(str+1);lenx=(int)strlen(x+1);pii num1=mkpr(1,1),num2=mkpr(1,1);
	for(int i=1;i<=lenx;i++)nowx.fir=(10ll*nowx.fir+(x[i]-'0'))%mod1,nowx.sec=(10ll*nowx.sec+(x[i]-'0'))%mod2;
	for(int i=1;i<=lenx;i++)num1.fir=10ll*num1.fir%mod1,num1.sec=10ll*num1.sec%mod2;
	for(int i=1;i<lenx;i++)num2.fir=10ll*num2.fir%mod1,num2.sec=10ll*num2.sec%mod2;
	for(int i=1;i<=lenx;i++)
		sum1[lenx].fir=(10ll*sum1[lenx].fir+1ll*(str[i]-'0'))%mod1,
		sum1[lenx].sec=(10ll*sum1[lenx].sec+1ll*(str[i]-'0'))%mod2;
	for(int i=1;i<lenx;i++)
		sum2[lenx-1].fir=(10ll*sum2[lenx-1].fir+1ll*(str[i]-'0'))%mod1,
		sum2[lenx-1].sec=(10ll*sum2[lenx-1].sec+1ll*(str[i]-'0'))%mod2;
	for(int i=lenx+1;i<=lens;i++)
		sum1[i].fir=(10ll*sum1[i-1].fir+1ll*(str[i]-'0')-1ll*num1.fir*(str[i-lenx]-'0')%mod1+1ll*mod1)%mod1,
		sum1[i].sec=(10ll*sum1[i-1].sec+1ll*(str[i]-'0')-1ll*num1.sec*(str[i-lenx]-'0')%mod2+1ll*mod2)%mod2;
	for(int i=lenx;i<=lens;i++)
		sum2[i].fir=(10ll*sum2[i-1].fir+1ll*(str[i]-'0')-1ll*num2.fir*(str[i-lenx+1]-'0')%mod1+1ll*mod1)%mod1,
		sum2[i].sec=(10ll*sum2[i-1].sec+1ll*(str[i]-'0')-1ll*num2.sec*(str[i-lenx+1]-'0')%mod2+1ll*mod2)%mod2;
	for(int i=lenx+lenx-2;i<=lens;i++){
		if(i>=lenx+lenx&&sum1[i]+sum1[i-lenx]==nowx){printf("%d %d\\n%d %d\\n",i-lenx-lenx+1,i-lenx,i-lenx+1,i);return 0;}
		if(lenx>1&&i>=lenx+lenx-1&&sum1[i]+sum2[i-lenx]==nowx){printf("%d %d\\n%d %d\\n",i-lenx-lenx+2,i-lenx,i-lenx+1,i);return 0;}
		if(lenx>1&&i>=lenx+lenx-1&&sum2[i]+sum1[i-lenx+1]==nowx){printf("%d %d\\n%d %d\\n",i-lenx-lenx+2,i-lenx+1,i-lenx+2,i);return 0;}
		if(lenx>1&&sum2[i]+sum2[i-lenx+1]==nowx){printf("%d %d\\n%d %d\\n",i-lenx-lenx+3,i-lenx+1,i-lenx+2,i);return 0;}
	}
	for(int i=lenx+1;i<=lens;i++){
		bool flag=0;
		for(int j=1;j<=min(10,lenx);j++)if(str[i-lenx+j]^x[j])flag=1;
		if(flag&&lenx>10)continue;pii summ=mkpr(0,0),num=mkpr(1,1);
		for(int j=1;j<=min(lenx,i-lenx);j++){
			summ.fir=(1ll*summ.fir+1ll*num.fir*(str[i-lenx-j+1]-'0'))%mod1;
			summ.sec=(1ll*summ.sec+1ll*num.sec*(str[i-lenx-j+1]-'0'))%mod2;
			if(sum1[i]+summ==nowx){printf("%d %d\\n%d %d\\n",i-lenx-j+1,i-lenx,i-lenx+1,i);return 0;}
			num.fir=10ll*num.fir%mod1;num.sec=10ll*num.sec%mod2;
		}
		summ=mkpr(0,0);
		for(int j=1;j<=min(lenx,lens-i);j++){
			summ.fir=(10ll*summ.fir+str[i+j]-'0')%mod1;
			summ.sec=(10ll*summ.sec+str[i+j]-'0')%mod2;
			if(sum1[i]+summ==nowx){printf("%d %d\\n%d %d\\n",i-lenx+1,i,i+1,i+j);return 0;}
		}
		num=mkpr(1,1);summ=mkpr(0,0);
		for(int j=1;j<=min(lenx-1,i-lenx+1);j++){
			summ.fir=(1ll*summ.fir+1ll*num.fir*(str[i-lenx-j+2]-'0'))%mod1;
			summ.sec=(1ll*summ.sec+1ll*num.sec*(str[i-lenx-j+2]-'0'))%mod2;
			if(sum2[i]+summ==nowx){printf("%d %d\\n%d %d\\n",i-lenx-j+2,i-lenx+1,i-lenx+2,i);return 0;}
			num.fir=10ll*num.fir%mod1;num.sec=10ll*num.sec%mod2;
		}
		summ=mkpr(0,0);
		for(int j=1;j<=min(lenx-1,lens-i);j++){
			summ.fir=(10ll*summ.fir+str[i+j]-'0')%mod1;
			summ.sec=(10ll*summ.sec+str[i+j]-'0')%mod2;
			if(sum2[i]+summ==nowx){printf("%d %d\\n%d %d\\n",i-lenx+2,i,i+1,i+j);return 0;}
		}
	}
	return 0;
}

谢谢!!!

以上是关于[CF1598G]The Sum of Good Numbers的主要内容,如果未能解决你的问题,请参考以下文章

CF1006C Three Parts of the Array

「CF622F」The Sum of the k-th Powers「拉格朗日插值」

CF622F The Sum of the k-th Powers (拉格朗日插值)

C - The Number Of Good Substrings CodeForces - 1217C

[题解] CF85D Sum of Medians

CF616E Sum of Remainders(分块&取模)