2025牛客暑期多校训练营8 J Multiplication in Base the Square Root of -2

J.Multiplication in Base the Square Root of -2

题意:

给定两个\(\sqrt {-2}\)进制数,求他们的乘积。

思路:

首先不要去考虑\(\sqrt {-2}\),而是将它作为一个未知数\(x\)。那么我们要求的是两个关于\(x\)的多项式的乘积。很自然地想到FFT。然后我们能够得到一个多项式,考虑如何去将它还原成\(\sqrt {-2}\)进制数。

根据定义,我们发现每一项的系数都是\(1\)\(0\),且\({(\sqrt {-2})}^2=-2\)。那么从小往大枚举,若当前第\(i\)项系数不为\(1\)\(0\),设为\(x\cdot {(\sqrt {-2})}^i\),则我们根据\(x\)的奇偶,取出\(2k\cdot {(\sqrt {-2})}^i\)使得当前第\(i\)项系数满足\(1\)\(0\),剩下部分\(2k\cdot {(\sqrt {-2})}^i=-k\cdot {(\sqrt {-2})}^{i+2}\),直接加到第\(i+2\)项系数上,整体过程类似进位。

整体时间复杂度就是FFT的复杂度\(O(nlogn)\).

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
constexpr int M=2e6+5e3;
const double pie=acos(-1.0);
struct comp{// 手打复数,避免被卡(其实一般也没有人来卡这个吧)。
	double real,img;
	comp(double xx=0,double yy=0){
		real=xx;
		img=yy;
	}
	comp operator + (const comp b)const{ 
		return comp(real+b.real , img+b.img);
	}
	comp operator - (const comp b)const{ 
		return comp(real-b.real , img-b.img);
	}
	comp operator * (const comp b)const{ 
		return comp(real*b.real-img*b.img , real*b.img+img*b.real);
	}
}f[M],g[M];
int n,m,l,lim=1;
int r[M];
void fft(comp *F,int oper){// oper 是操作,传入 1 是FFT,-1 是 IFFT。
	for(int i=0;i<lim;i++){
		if(i>r[i]-1){
			continue;
		}
		swap(F[i],F[r[i]]);
	}
	for(int mid=1;mid<lim;mid<<=1){
		comp wn(cos(pie/mid),oper*sin(pie/mid));
		for(int R=mid<<1,j=0;j<lim;j+=R){
			comp w(1.0,0.0);
			for(int k=0;k<mid;k++,w=w*wn){
				comp y=F[j+k],z=w*F[j+mid+k];
				F[j+k]=y+z;
				F[j+mid+k]=y-z;
			}
		}
	}
}
string s1,s2;
int a[M];
void solve(){
	cin>>s1>>s2;
	n=s1.size()-1;
	m=s2.size()-1;
	for(int i=0;i<=(n+m)*2+2;i++){
		a[i]=r[i]=0;
		f[i]=g[i]={0,0};
	}
	for(int i=0;i<=n;i++){
		f[i].real=s1[n-i]-'0';
	}
	for(int i=0;i<=m;i++){
		g[i].real=s2[m-i]-'0';
	}
	lim=1;
	l=0;
	while(lim<n+m+1){
		lim<<=1;
		l++;
	}
	for(int i=0;i<lim;i++){
		r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
	}
	fft(f,1);
	fft(g,1);
	for(int i=0;i<lim;i++){
		f[i]=f[i]*g[i];
	}
	fft(f,-1);
	int len=n+m+1;
	for(int i=0;i<len;i++){
		if(i<n+m+1)a[i]+=(int)(f[i].real/lim+0.5);
		if(a[i]>1){
			a[i+2]-=a[i]/2;
			a[i]%=2;
			if(i+2>=len){
				len=i+3;
			}
		}else if(a[i]<0){
			int t=(-a[i]+1)/2;
			a[i+2]+=t;
			a[i]=(-a[i])%2;
			if(i+2>=len){
				len=i+3;
			}
		}
	}
	while (a[len] == 0 && len > 0) len--;
	
	for (int i = len; i >= 0; i--) cout << a[i];
	cout<<"\n";
}
signed main() {
	cin.tie(nullptr)->sync_with_stdio(false);
	int t = 1;
//	freopen("in.txt", "r", stdin);
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}


posted @ 2025-08-07 17:51  ptlks  阅读(41)  评论(0)    收藏  举报