NTT 알고리즘 에서 소수 선택

4744 단어 수필
이 소 수 를 N 으로 설정 하면 N - 1 은 n 보다 작은 2 의 차방 으로 정 리 될 수 있어 야 합 니 다. 항상 2 의 차방 길 이 를 나 누 어야 하기 때문에 정 리 될 수 있어 야 합 니 다. 그래서 N 은 m * 2 ^ k + 1 의 길 이 를 표시 할 수 있 습 니 다. 그 다음 에 다른 2 ^ k > = ntt 길이 의 소 수 를 시험 해 보 았 는데 결과 가 정확 하지 않 았 습 니 다. 나중에 N 은 최대 볼 륨 결과 N * max {a [i]} * {b [i]} 보다 커 야 한 다 는 것 을 알 게 되 었 습 니 다.그렇지 않 으 면 mod 에 오류 가 생 길 수 있 습 니 다. 그 후에 저 는 본원 의 존재 성 증명 서 를 다시 한 번 보 았 습 니 다. 그 큰 사람 은 한 마디 로 증명 되 었 습 니 다. 어떤 군 론 에서 기초 지식 이 라 고 하 는 지 알 지 못 했 습 니 다. 갑자기 자신 이 수론 에 대해 하 얗 게 생각 했 습 니 다. 인 코딩 수업 에서 본원 적 인 것 을 배 운 것 같 지만 증명 할 것 이 없 었 습 니 다. 결론 만 있 고 과정 이 없 는 것 같 습 니 다.
    하지만 FFT 에 적용 되 는 장면 이 더 많다 고 생각 합 니 다. 정밀도 에 문제 가 있 지만.
    두 세 달 전에 쓴 NTT 문 제 를 붙 이 고 지나 가 는 길에 필요 한 것 은 참고 하 세 요 (hihocoder 1388, fft 판 포함)
#include 
#include 
#include 
#include 
#pragma warning(disable:4996)
using namespace std;
const int g = 3;
const long long int mymod = 31525197391593473LL;
int revg;
const double pi = acos(-1.0);
const int bign = 100033;
struct complex
{
	double r, v;
	complex()
	{ 
		r = 0.0;
		v = 0.0;
	}


	complex(double r1, double v1)
	{
		r = r1;
		v = v1;
	}
	complex operator+(const complex& ano)
	{
		return complex(r + ano.r,  v + ano.v);
	}
	complex operator-(const complex& ano)
	{
		return complex(r - ano.r, v - ano.v);
	}
	complex operator*(const complex& ano)
	{
		return complex(r * ano.r - v * ano.v, r * ano.v + v * ano.r);
	}
	complex operator/(double r1)
	{
		return complex(r / r1, v / r1);
	}
}a[4*bign],b[4*bign];


long long int mymul(long long int ta, long long int tb)
{
	long long int res = 0;
	for (;tb; tb >>= 1)
	{
		if (tb & 1)
			res = (res + ta) % mymod;
		ta = (ta << 1) % mymod;
	}
	return res;
}


long long mul(long long x, long long y) {
	return (x * y - (long long)(x / (long double)mymod * y + 1e-3) * mymod + mymod) % mymod;
}
long long int quickpow(long long ta, long long int tb)
{
	long long res = 1;
	for (; tb; tb >>= 1)
	{
		if (tb & 1)
			res = mul(res, ta);
		ta = mul(ta, ta);
	}
	return res;
}
int rev(int num, int len)
{
	int ans = 0;
	for (int i = 1,j = 0; j i)
			swap(c[i], c[j]);
	}


	//long long int tg = g;
	//if (on == -1)
	//	tg = quickpow(g, mymod - 2);
	for (int i = 2; i <= tlen; i <<= 1)
	{
		long long int wn = quickpow(g,(mymod-1)/i);
		if (on == -1)
			wn = quickpow(wn, mymod-2);
		for (int j = 0; j < tlen; j += i)
		{
			long long int w = 1;
			for (int k = j; k < j + i / 2; k++)
			{
				long long int u = c[k];
				long long int v = mul(w , c[k + i / 2]);
				c[k] = (u + v) % mymod;
				c[k + i / 2] = (u - v + mymod) % mymod;
			//	long long int oldw = w;
				w = mul(w, wn);
			}
		}
	}
	if (on == -1)
	{
		//for (int i = 0; i < tlen / 2; i++)
		//{
		//	swap(c[i], c[tlen - i - 1]);
		//}
		for (int i = 0; i < tlen; i++)
			c[i] = mul(c[i], quickpow(tlen, mymod - 2));
	}
}


void FFT(complex c[], int len, int on)
{	
	int tlen = (1 << len);
	
	for (int i = 0; i < tlen; i++)
	{
		int j = rev(i,len);
		if (j > i)
			swap(c[i], c[j]);
	}


	for (int i = 2; i <= tlen; i <<= 1)
	{
		complex wn(cos(2*pi/i),on * sin(2*pi/i));
		for (int j = 0; j < tlen; j += i)
		{
			complex w(1,0);
			for (int k = j; k < j + i/2; k++)
			{
				complex u =  c[k];
				complex v = (w * c[k + i / 2]);
				c[k] = u + v;
				c[k + i / 2] = u - v;
				w = w * wn;
			}
		}
	}
	if (on == -1)
	{
		for (int i = 0; i < tlen; i++)
		{
			c[i].r /= tlen;
			c[i].v /= tlen;
		}
	}
}
long long int a1[4 * bign], b1[4 * bign];
int main()
{
	int T;
	//printf("%lld
", quickpow(g, mymod - 1)); scanf("%d", &T); while (T--) { int n; long long int ans = 0; scanf("%d", &n); for (int i = 0; i < n; i++) { int x; scanf("%d", &x); ans += 1ll * x * x; a1[i] = x; a1[i + n] = a1[i]; } for (int i = n - 1; i >= 0; i--) { int x; scanf("%d", &x); ans += 1ll * x * x; b1[i] = x; } int len = 0; int j; for (j = 1; j < 2 * n; j <<= 1,len++); for (int i = n; i < j; i++) b1[i] = 0; for (int i = 2 * n; i < j; i++) a1[i] = 0; NTT(a1, len, 1); NTT(b1, len, 1); for (int i = 0; i < j; i++) a1[i] = mul(a1[i],b1[i])%mymod; NTT(a1, len, -1); long long int tmax = 0; for (int i = n - 1; i < 2 * n - 1; i++) { long long int tmp = a1[i]; if (tmp > tmax) tmax = tmp; } printf("%lld
", ans - 2* tmax); } } /* 5 5 1000000 1000001 1000002 1000003 1000004 1000003 1000004 1000000 1000001 1000002 */

좋은 웹페이지 즐겨찾기