teamnote history merge
This commit is contained in:
14
2024fall/source/Math/CRT.cpp
Normal file
14
2024fall/source/Math/CRT.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
pll crt(pll p, pll q)
|
||||
{
|
||||
if(p.fi > q.fi) swap(p, q);
|
||||
auto [a, A] = p;
|
||||
auto [b, B] = q;
|
||||
|
||||
ll g = gcd(A, B);
|
||||
if((b-a)%g != 0) return {-1, -1};
|
||||
|
||||
ll i = A, j = B, k = b-a;
|
||||
i/=g; j/=g; k/=g;
|
||||
auto [x, y] = diophantos(i, j);
|
||||
return {(ll)((a+(lll)A*k*x)%(A*B/g)), A*B/g};
|
||||
}
|
||||
14
2024fall/source/Math/Diophantos.cpp
Normal file
14
2024fall/source/Math/Diophantos.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
pll diophantos(ll a, ll b)
|
||||
{
|
||||
assert(a>0 and b>=0);
|
||||
if(b == 0) return {1, 0};
|
||||
auto [y, x] = diophantos(b, a%b); y = y-(a/b)*x;
|
||||
if(x < 0 or x >= b)
|
||||
{
|
||||
ll t = x/b;
|
||||
if(x%b < 0) t--;
|
||||
|
||||
x -= b*t; y += a*t;
|
||||
}
|
||||
return {x, y};
|
||||
}
|
||||
83
2024fall/source/Math/FFTConv.cpp
Normal file
83
2024fall/source/Math/FFTConv.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
using cpx = complex<double>;
|
||||
using vcpx = vector<cpx>;
|
||||
void fft(vcpx &a, bool inv = false)
|
||||
{
|
||||
int n = a.size(), j = 0; assert((n&-n) == n);
|
||||
for(int i=1; i<n; i++)
|
||||
{
|
||||
int bit = (n >> 1);
|
||||
while(j >= bit)
|
||||
{
|
||||
j -= bit;
|
||||
bit >>= 1;
|
||||
}
|
||||
j += bit;
|
||||
if(i < j) swap(a[i], a[j]);
|
||||
}
|
||||
|
||||
vcpx roots(n/2);
|
||||
prec c = 2 * pi * (inv ? -1 : 1);
|
||||
for(int i=0; i<n/2; i++)
|
||||
roots[i] = cpx(cosl(c * i / n), sinl(c * i / n));
|
||||
|
||||
for(int i=2; i<=n; i<<=1)
|
||||
{
|
||||
int step = n / i;
|
||||
for(int j=0; j<n; j+=i)
|
||||
{
|
||||
for(int k=0; k<i/2; k++)
|
||||
{
|
||||
cpx u = a[j+k], v = a[j+k+i/2]*roots[step*k];
|
||||
a[j+k] = u+v;
|
||||
a[j+k+i/2] = u-v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(inv) for(int i=0; i<n; i++) a[i] /= n;
|
||||
}
|
||||
|
||||
ll mod = 1e9+7;
|
||||
vl conv(const vl& AA,const vl& BB)
|
||||
{
|
||||
const ll G = 1<<15;
|
||||
int n = AA.size()+BB.size()-1;
|
||||
int m = 1; while(m < n) m<<=1;
|
||||
|
||||
int a = AA.size(), b = BB.size();
|
||||
|
||||
vcpx A(m), B(m), C(m), D(m);
|
||||
fors(i, 0, a-1) A[i] = cpx(AA[i]/G, AA[i]%G);
|
||||
fors(i, 0, b-1) B[i] = cpx(BB[i]/G, BB[i]%G);
|
||||
|
||||
fft(A); fft(B);
|
||||
|
||||
fors(i, 0, m-1)
|
||||
{
|
||||
int j = i?m-i:0;
|
||||
cpx A1 = (A[i]+conj(A[j]))*cpx(0.5, 0);
|
||||
cpx A2 = (A[i]-conj(A[j]))*cpx(0, -0.5);
|
||||
|
||||
cpx B1 = (B[i]+conj(B[j]))*cpx(0.5, 0);
|
||||
cpx B2 = (B[i]-conj(B[j]))*cpx(0, -0.5);
|
||||
|
||||
C[i] = A1*B1 + A2*B2*cpx(0, 1);
|
||||
D[i] = A2*B1 + A1*B2*cpx(0, 1);
|
||||
}
|
||||
|
||||
fft(C, true); fft(D, true);
|
||||
|
||||
|
||||
vl ret(m); ll G1 = G%mod, G2 = (lll)G*G%mod;
|
||||
fors(i, 0, m-1)
|
||||
{
|
||||
ll p = ll(C[i].real()+0.5);
|
||||
ll q = ll(D[i].real()+0.5) + ll(D[i].imag()+0.5);
|
||||
ll r = ll(C[i].imag()+0.5);
|
||||
|
||||
p %= mod; q %= mod; r %= mod;
|
||||
ret[i] = (((lll)p*G2)%mod+((lll)q*G1)%mod+r%mod)%mod;
|
||||
}
|
||||
ret.resize(n);
|
||||
return ret;
|
||||
}
|
||||
8
2024fall/source/Math/FloorSum.cpp
Normal file
8
2024fall/source/Math/FloorSum.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
ll floor_sum(ll a, ll b, ll c, ll n)
|
||||
{
|
||||
if(a>=c or b>=c) return n*(n-1)/2 * (a/c) + n * (b/c) + floor_sum(a%c, b%c, c, n);
|
||||
if(a == 0) return b/c*n;
|
||||
|
||||
ll m = (a*(n-1)+b)/c;
|
||||
return m*(n-1) - floor_sum(c, c-b-1, a, m);
|
||||
}
|
||||
7
2024fall/source/Math/Harmonic.cpp
Normal file
7
2024fall/source/Math/Harmonic.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
ll f(int n)
|
||||
{
|
||||
ll ans = 0;
|
||||
for(int i = 1; i <= n; i = n/(n/i)+ 1)
|
||||
ans += (ll)(n/(n/i)-i+1)*(n/i);
|
||||
return ans;
|
||||
}
|
||||
31
2024fall/source/Math/MillerRabin.cpp
Normal file
31
2024fall/source/Math/MillerRabin.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
ll pow(ll a, ll b, ll mod)
|
||||
{
|
||||
ll ret = 1;
|
||||
for(int st=0; (1LL<<st) <= b; st++)
|
||||
{
|
||||
if((1LL<<st) & b) ret=(lll)ret*a%mod;
|
||||
a=(lll)a*a%mod;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
bool miller(ll n, ll a)
|
||||
{
|
||||
if(n == a) return true;
|
||||
ll x = n-1;
|
||||
if(pow(a, x, n) != 1) return false;
|
||||
while(x%2==0)
|
||||
{
|
||||
x/=2;
|
||||
ll t = pow(a, x, n);
|
||||
if(t!=1 and t!=n-1) return false;
|
||||
if(t==n-1) return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool is_p(ll n)
|
||||
{
|
||||
if(n<=2) return n==2;
|
||||
vi D = {2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 37};
|
||||
for(auto i:D) if(!miller(n, i)) return false;
|
||||
return true;
|
||||
}
|
||||
97
2024fall/source/Math/NTT.cpp
Normal file
97
2024fall/source/Math/NTT.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
namespace GMS
|
||||
{
|
||||
template<ll mod>
|
||||
ll pow(ll a, ll b)
|
||||
{
|
||||
static_assert(mod <= (ll)2e9, "mod should be less than 2e9");
|
||||
a %= mod;
|
||||
ll ret = 1;
|
||||
while(b != 0)
|
||||
{
|
||||
if(b&1) ret = ret*a%mod;
|
||||
a = a*a%mod; b>>=1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
template<ll mod, ll w>
|
||||
void ntt(vector<ll> &a, bool inv = false)
|
||||
{
|
||||
static_assert(mod <= (ll)2e9, "mod should be less than 2e9");
|
||||
int n = a.size(), j = 0;
|
||||
|
||||
assert((n & -n) == n);
|
||||
assert((mod-1)%n == 0);
|
||||
|
||||
for(int i=1; i<n; i++)
|
||||
{
|
||||
int bit = (n >> 1);
|
||||
while(j >= bit){
|
||||
j -= bit;
|
||||
bit >>= 1;
|
||||
}
|
||||
j += bit;
|
||||
if(i < j) swap(a[i], a[j]);
|
||||
}
|
||||
|
||||
static vector<ll> root[30], iroot[30];
|
||||
for(int st=1; (1<<st) <= n; st++)
|
||||
{
|
||||
if(root[st].empty())
|
||||
{
|
||||
ll t = pow<mod>(w, (mod-1)/(1<<st));
|
||||
|
||||
root[st].pb(1);
|
||||
for(int i=1; i<(1<<(st-1)); i++)
|
||||
root[st].pb(root[st].back()*t%mod);
|
||||
}
|
||||
if(iroot[st].empty())
|
||||
{
|
||||
ll t = pow<mod>(w, (mod-1)/(1<<st));
|
||||
t = pow<mod>(t, mod-2);
|
||||
|
||||
iroot[st].pb(1);
|
||||
for(int i=1; i<(1<<(st-1)); i++)
|
||||
iroot[st].pb(iroot[st].back()*t%mod);
|
||||
}
|
||||
}
|
||||
|
||||
vector<ll>* r = (inv?root:iroot);
|
||||
|
||||
for(int st = 1; (1<<st) <= n; st++)
|
||||
{
|
||||
int i = 1<<st; //int step = n / i;
|
||||
for(int j=0; j<n; j+=i)
|
||||
{
|
||||
for(int k=0; k<i/2; k++)
|
||||
{
|
||||
ll u = a[j+k], v = a[j+k+i/2] * r[st][k]%mod;
|
||||
a[j+k] = (u+v)%mod;
|
||||
a[j+k+i/2] = (mod+u-v)%mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(inv)
|
||||
{
|
||||
ll in = pow<mod>(n, mod-2);
|
||||
for(int i=0; i<n; i++) a[i] = a[i]*in%mod;
|
||||
}
|
||||
}
|
||||
|
||||
template<ll mod, ll w>
|
||||
vl conv(vl A, vl B)
|
||||
{
|
||||
int n = A.size(), m = B.size();
|
||||
int t = 1; while(t < n+m-1) t*=2;
|
||||
A.resize(t); B.resize(t);
|
||||
|
||||
ntt<mod, w>(A); ntt<mod, w>(B);
|
||||
|
||||
fors(i, 0, t-1) A[i] = A[i]*B[i]%mod;
|
||||
|
||||
ntt<mod, w>(A, true);
|
||||
A.resize(n+m-1);
|
||||
|
||||
return A;
|
||||
}
|
||||
} // namespace GMS
|
||||
32
2024fall/source/Math/PolladRho.cpp
Normal file
32
2024fall/source/Math/PolladRho.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
void fact(ll n, vl& ret)
|
||||
{
|
||||
if(n == 1) return;
|
||||
if(n%2 == 0)
|
||||
{
|
||||
ret.pb(2);
|
||||
fact(n/2, ret);
|
||||
return;
|
||||
}
|
||||
if(is_p(n))
|
||||
{
|
||||
ret.pb(n);
|
||||
return;
|
||||
}
|
||||
|
||||
ll a, b, c, g = n;
|
||||
auto f = [&c, &n](ll x)->ll{return (c+(lll)x*x)%n;};
|
||||
do
|
||||
{
|
||||
if(g == n) a=b=rand()%(n-2)+2, c=rand()%20+1;
|
||||
a=f(a); b=f(f(b));
|
||||
g = gcd(a-b, n);
|
||||
}while(g == 1);
|
||||
fact(g, ret); fact(n/g, ret);
|
||||
}
|
||||
vl po_rho(ll n)
|
||||
{
|
||||
vl ret;
|
||||
fact(n, ret);
|
||||
sort(all(ret));
|
||||
return ret;
|
||||
}
|
||||
287
2024fall/source/Math/Polynomial.cpp
Normal file
287
2024fall/source/Math/Polynomial.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
namespace GMS
|
||||
{
|
||||
template<ll T, ll mod, ll w>
|
||||
struct Qring : public vl
|
||||
{
|
||||
using poly = Qring<T, mod, w>;
|
||||
Qring() : vl(1, 0){}
|
||||
Qring(ll c) : vl(1, c){}
|
||||
Qring(ll c, int n) : vl(n, c){}
|
||||
Qring(const vl& cp) : vl(cp){}
|
||||
|
||||
ll& operator[](ll idx)
|
||||
{
|
||||
if((unsigned)idx < size()) return vl::operator[](idx);
|
||||
this->resize(idx+1); return vl::operator[](idx);
|
||||
}
|
||||
ll operator[](ll idx) const
|
||||
{
|
||||
if((unsigned)idx < size()) return vl::operator[](idx);
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
void adjust()
|
||||
{
|
||||
while(size() > T) pop_back();
|
||||
while(size() > 1 and back() == 0) pop_back();
|
||||
}
|
||||
void adjust(int n){resize(n, 0);}
|
||||
|
||||
ll operator()(ll x)
|
||||
{
|
||||
x %= mod;
|
||||
ll ret = 0;
|
||||
for(auto it=rbegin(); it!=rend(); it++)
|
||||
ret = (ret*x+*it)%mod;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend poly operator%(const poly& A, int B) // remainder by x^B
|
||||
{
|
||||
poly ret(A);
|
||||
ret.resize(B, 0);
|
||||
return ret;
|
||||
}
|
||||
friend poly operator%(poly&& A, int B) // remainder by x^B
|
||||
{
|
||||
A.resize(B, 0);
|
||||
return A;
|
||||
}
|
||||
|
||||
friend poly operator+(const poly& A, const poly& B)
|
||||
{
|
||||
int n = max(A.size(), B.size());
|
||||
poly ret(0, n);
|
||||
fors(i, 0, n-1) ret[i] = (A[i]+B[i])%mod;
|
||||
ret.adjust();
|
||||
return ret;
|
||||
}
|
||||
friend poly operator+(poly&& A, const poly& B)
|
||||
{
|
||||
int n = B.size();
|
||||
fors(i, 0, n-1) A[i] = (A[i]+B[i])%mod;
|
||||
A.adjust();
|
||||
return A;
|
||||
}
|
||||
|
||||
friend poly operator-(const poly& A)
|
||||
{
|
||||
int n = A.size();
|
||||
poly ret(0, n);
|
||||
fors(i, 0, n-1) ret[i] = A[i]?mod-A[i]:0;
|
||||
return ret;
|
||||
}
|
||||
friend poly operator-(poly&& A)
|
||||
{
|
||||
int n = A.size();
|
||||
fors(i, 0, n-1) A[i] = A[i]?mod-A[i]:0;
|
||||
return A;
|
||||
}
|
||||
|
||||
friend poly operator-(const poly& A, const poly& B)
|
||||
{
|
||||
int n = max(A.size(), B.size());
|
||||
poly ret(0, n);
|
||||
fors(i, 0, n-1) ret[i] = (mod+A[i]-B[i])%mod;
|
||||
ret.adjust();
|
||||
return ret;
|
||||
}
|
||||
friend poly operator-(poly&& A, const poly& B)
|
||||
{
|
||||
int n = B.size();
|
||||
fors(i, 0, n-1) A[i] = (mod+A[i]-B[i])%mod;
|
||||
A.adjust();
|
||||
return A;
|
||||
}
|
||||
|
||||
friend poly operator*(ll x, const poly& B)
|
||||
{
|
||||
poly ret(B); x %= mod;
|
||||
for(auto &i : ret) i = (i*x)%mod;
|
||||
ret.adjust();
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend poly operator*(const poly& A, const poly& B)
|
||||
{
|
||||
poly ret(conv<mod, w>(A, B));
|
||||
// ACL : poly ret(atcoder::convolution<mod>(A, B));
|
||||
ret.adjust();
|
||||
return ret;
|
||||
}
|
||||
//friend poly operator/(const poly& A, const poly& B){return A*inv(B);}
|
||||
|
||||
friend poly inv(const poly& A){return inv(A, T);}
|
||||
friend poly inv(const poly& A, int t)
|
||||
{
|
||||
assert(A[0] != 0);
|
||||
poly g = pow<mod>(A[0], mod-2);
|
||||
|
||||
int st=1;
|
||||
while(st <= t)
|
||||
{
|
||||
st <<=1;
|
||||
g = (-A%st*g%st+2)*g%st;
|
||||
}
|
||||
g.adjust(t);
|
||||
return g;
|
||||
}
|
||||
|
||||
friend poly diff(const poly& A)
|
||||
{
|
||||
int n = A.size();
|
||||
poly ret(0, n-1);
|
||||
forr(i, n-1) ret[i-1] = i*A[i]%mod;
|
||||
return ret;
|
||||
}
|
||||
friend poly inte(const poly& A)
|
||||
{
|
||||
static ll inv[T] = {0, };
|
||||
int n = A.size();
|
||||
poly ret(0, n+1);
|
||||
forr(i, n+1) if(inv[i] == 0) inv[i] = pow<mod>(i, mod-2);
|
||||
forr(i, n+1) ret[i] = inv[i]*A[i-1]%mod;
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend poly log(const poly& A){return log(A, T);}
|
||||
friend poly log(const poly& A, int t)
|
||||
{
|
||||
assert(A[0] == 1);
|
||||
poly ret = inte(diff(A) * inv(A, t)%t);
|
||||
ret.adjust(t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend poly exp(const poly& A){return exp(A, T);}
|
||||
friend poly exp(const poly& A, int t)
|
||||
{
|
||||
assert(A[0] == 0);
|
||||
|
||||
poly g = 1;
|
||||
int st = 1;
|
||||
while(st < t)
|
||||
{
|
||||
st <<= 1;
|
||||
g = (A%st-log(g, st)+1)*g%st;
|
||||
}
|
||||
g.adjust(t);
|
||||
return g;
|
||||
}
|
||||
|
||||
friend poly pow(const poly& A, ll b, ll t)
|
||||
{
|
||||
poly ret(A); ret.adjust();
|
||||
if(ret.size() == 1)
|
||||
{
|
||||
ret[0] = pow<mod>(ret[0], b);
|
||||
ret.adjust(t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ll idx = 0; while(ret[idx] == 0) idx++;
|
||||
if((__int128_t) idx * b >= t) return poly(0, t);
|
||||
|
||||
ll c = ret[idx]; ll ic = pow<mod>(ret[idx], mod-2); poly g;
|
||||
int n = ret.size();
|
||||
fors(i, idx, n-1) g[i-idx] = ret[i]*ic%mod;
|
||||
g.resize(t-idx*b);
|
||||
|
||||
g = exp(b * log(g, t-idx*b), t-idx*b);
|
||||
c = pow<mod>(c, b);
|
||||
|
||||
ret = poly(0, t);
|
||||
fors(i, idx*b, t-1) ret[i] = g[i-idx*b] * c % mod;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Only just Polynomial, not Qring
|
||||
void rev()
|
||||
{
|
||||
int n=size();
|
||||
poly& F = *this;
|
||||
for(int i=0; i<n/2; i++) std::swap(F[i], F[n-i-1]);
|
||||
}
|
||||
friend poly div_quot(poly F, poly G)
|
||||
{
|
||||
F.adjust(); G.adjust();
|
||||
ll df = F.size(), dg = G.size();
|
||||
if(df < dg) return poly(0);
|
||||
|
||||
F.rev(); G.rev();
|
||||
|
||||
F.resize(df-dg+1);
|
||||
F = F * inv(G, df-dg+1);
|
||||
F.resize(df-dg+1);
|
||||
|
||||
F.rev();
|
||||
return F;
|
||||
}
|
||||
friend poly div_rem(poly F, poly G)
|
||||
{return F-G*div_quot(F, G);}
|
||||
|
||||
friend poly shift(const poly& F, ll c)
|
||||
{
|
||||
ll n = F.size(); c %= mod;
|
||||
|
||||
poly A(0, n); ll fac = 1;
|
||||
fors(i, 0, n-1) A[i] = F[i]*fac%mod, fac = fac*(i+1)%mod;
|
||||
A.rev();
|
||||
|
||||
poly C(1, n);
|
||||
fors(i, 1, n-1) C[i] = C[i-1]*c%mod;
|
||||
|
||||
ll facc = fac = pow<mod>(fac, mod-2)*n%mod;
|
||||
fore(i, n-1, 0) C[i] = C[i]*fac%mod, fac = fac*i%mod;
|
||||
|
||||
poly B = C*A; B.resize(n);
|
||||
B.rev();
|
||||
|
||||
fore(i, n-1, 0) B[i] = B[i]*facc%mod, facc = facc*i%mod;
|
||||
|
||||
return B;
|
||||
}
|
||||
friend void calcG(vector<poly>& G, int i, int l, int r, const vl& p)
|
||||
{
|
||||
if(l == r)
|
||||
{
|
||||
ll g = p[l]?mod-p[l]:0;
|
||||
G[i] = vl({g, 1});
|
||||
return;
|
||||
}
|
||||
int mid = (l+r)/2;
|
||||
calcG(G, i*2, l, mid, p);
|
||||
calcG(G, i*2+1, mid+1, r, p);
|
||||
|
||||
G[i] = G[i*2]*G[i*2+1];
|
||||
}
|
||||
friend void eval(const vector<poly>& G, int i, int l, int r, poly&& F, vl& ret)
|
||||
{
|
||||
if(l == r)
|
||||
{
|
||||
ret[l] = F[0];
|
||||
return;
|
||||
}
|
||||
|
||||
int mid=(l+r)/2;
|
||||
eval(G, i*2, l, mid, div_rem(F, G[i*2]), ret);
|
||||
eval(G, i*2+1, mid+1, r, div_rem(F, G[i*2+1]), ret);
|
||||
}
|
||||
friend vl multipoint_eval(const poly& A, const vl& B)
|
||||
{
|
||||
int m = B.size();
|
||||
vector<poly> G(4*m);
|
||||
calcG(G, 1, 0, m-1, B);
|
||||
|
||||
vl ret(m, 0);
|
||||
eval(G, 1, 0, m-1, div_rem(A, G[1]), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
} // namespace GMS
|
||||
|
||||
const ll mod = 998244353, w = 3, T = 1<<20;
|
||||
using poly = GMS::Qring<T, mod, w>;
|
||||
Reference in New Issue
Block a user