一些模板
这里放一些自己写的代码模板吧。
Modint
template<int Mod, class T = unsigned> struct Modint {
T v;
Modint(T _v = 0) : v(_v) {}
Modint operator -() const {return v ? Mod - v : *this;}
Modint &operator += (const Modint &x) {return (v += x.v) >= Mod ? v -= Mod : v, *this;}
Modint &operator -= (const Modint &x) {return (v += Mod - x.v) >= Mod ? v -= Mod : v, *this;}
Modint &operator *= (const Modint &x) {return v = 1llu * v * x.v % Mod, *this;}
Modint &operator /= (const Modint &x) {return *this *= x.inv();}
Modint pow(long long B) const {
Modint res = 1, base = *this;
while (B) {
if (B & 1) res *= base;
base *= base, B >>= 1;
}
return res;
}
Modint inv() const {return pow(Mod - 2);}
friend Modint operator + (const Modint &A, const Modint &B) {return Modint(A) += B;}
friend Modint operator - (const Modint &A, const Modint &B) {return Modint(A) -= B;}
friend Modint operator * (const Modint &A, const Modint &B) {return Modint(A) *= B;}
friend Modint operator / (const Modint &A, const Modint &B) {return Modint(A) /= B;}
friend istream &operator >> (istream &A, Modint &B) {return A >> B.v;}
friend ostream &operator << (ostream &A, const Modint &B) {return A << B.v;}
friend bool operator == (const Modint &A, const Modint &B) {return A.v == B.v;}
explicit operator bool() const {return v;}
};
typedef Modint<mod> mint;
可以使用 cin
,cout
输出。
FastIO
namespace FastIO {
const int MaxBuf = 1e6;
using namespace std;
class Istream {
private:
char buffer[MaxBuf + 5], *p1 = buffer, *p2 = buffer;
inline char getchar() {
if (p1 == p2) {
p1 = buffer;
p2 = buffer + fread(buffer, 1, MaxBuf, stdin);
}
if (p1 == p2) return EOF;
else return *p1++;
}
template<typename Type>
Type getInteger() {
Type x = 0;
bool isNagetive = false;
char buf = getchar();
while (buf < '0' || buf > '9') {
isNagetive = buf == '-' ? true : false;
buf = getchar();
}
while (buf >= '0' && buf <= '9') {
x = x * 10 + (buf ^ 48);
buf = getchar();
}
return isNagetive ? -x : x;
}
template<typename Type>
Type getFloat() {
Type left = 0, right = 0;
bool isNagetive = false;
char buf = getchar();
while (buf < '0' || buf > '9') {
isNagetive = buf == '-' ? true : false;
buf = getchar();
}
while (buf >= '0' && buf <= '9') {
left = left * 10 + (buf ^ 48);
buf = getchar();
}
if (buf == '.') {
buf = getchar();
double mul = 10;
while (buf >= '0' && buf <= '9') {
right += (buf ^ 48) / mul;
buf = getchar(), mul *= 10;
}
}
return isNagetive ? -left - right : left + right;
}
char getChar() {
char buf = getchar();
while (isspace(buf))
buf = getchar();
return buf;
}
string getString() {
static char str[MaxBuf + 5], buf, *p;
string result;
p = str;
buf = getchar();
while (isspace(buf))
buf = getchar();
while (!isspace(buf)) {
*p++ = buf, buf = getchar();
if (p == str + MaxBuf) {
*p = 0;
result.append(str);
p = str;
}
}
*p = 0;
result.append(str);
return result;
}
public:
Istream() {}
~Istream() {}
template<typename Type>
inline Istream &operator >> (Type &x) {
if (is_same<Type, char>::value)
x = getChar();
else if (is_integral<Type>::value ||
is_same<Type, __int128_t>::value ||
is_same<Type, __uint128_t>::value)
x = getInteger<Type>();
else if (is_floating_point<Type>::value)
x = getFloat<Type>();
return *this;
}
inline Istream operator >> (string &x) {
x = getString();
return *this;
}
};
class Ostream {
private:
char buffer[MaxBuf + 5], *p1 = buffer;
unsigned precision;
const double eps = 1e-10;
#ifndef __WIN32
void putchar(const char c) {
if (p1 - buffer == MaxBuf) {
fwrite(buffer, 1, MaxBuf, stdout);
p1 = buffer;
}
*p1++ = c;
}
#endif
template<typename Type>
void putInteger(Type x) {
if (x < 0)
putchar('-'), x = -x;
static char buf[50], *p;
p = buf;
do *p++ = x % 10, x /= 10; while(x);
do putchar((*--p) ^ 48); while (p != buf);
}
template<typename Type>
void putFloat(Type x) {
if (x < 0)
putchar('-'), x = -x;
x += x * eps;
x = roundl(x * powl(10, precision)) / powl(10, precision);
Type left = floorl(x), right = x - left;
right += right * eps;
static char buf[MaxBuf + 5], *p;
p = buf;
do {
*p++ = left - (floorl(left / 10) * 10);
left /= 10;
} while (left >= 1);
do putchar((*--p) ^ 48); while (p != buf);
if (precision > 0) {
putchar('.');
for (unsigned i = 0; i < precision; ++i) {
right *= 10;
putchar((int)(floorl(right)) ^ 48);
right -= floorl(right);
}
}
}
void putString(string str) {
int len = str.length();
for (int i = 0; i < len; ++i)
putchar(str[i]);
}
public:
Ostream() {precision = 4;}
~Ostream() {}
inline void flush() {
fwrite(buffer, 1, p1 - buffer, stdout);
}
inline void setprecision(unsigned newprecision) {
precision = newprecision;
}
template<typename Type>
inline Ostream &operator << (const Type x) {
if (is_same<Type, char>::value)
putchar(x);
else if (is_integral<Type>::value ||
is_same<Type, __int128_t>::value ||
is_same<Type, __uint128_t>::value)
putInteger(x);
return *this;
}
inline Ostream &operator << (const float x) {
return putFloat<float>(x), *this;
}
inline Ostream &operator << (const double x) {
return putFloat<double>(x), *this;
}
inline Ostream &operator << (const long double x) {
return putFloat<long double>(x), *this;
}
inline Ostream &operator << (const char *x) {
return putString(x), *this;
}
inline Ostream &operator << (const string x) {
return putString(x), *this;
}
};
Istream fin;
Ostream fout;
}
using FastIO::fin;
using FastIO::fout;
用法同 cin
,cout
。用 fout.flush()
刷新缓冲区,fout.setprecision()
设置小数位数。
当小数位数过多的时候,超过 \(10^{-6}\) 后不建议使用 fout
,精度问题很大。
平时用的代码模板
// Cirno is not baka!
#include <bits/stdc++.h>
#define For(i, a, b) for (int i = (a); i <= (int)(b); ++i)
#define Rof(i, a, b) for (int i = (a); i >= (int)(b); --i)
#define Debug(...) { \
fprintf(stderr, "Function{%s},line[%d]:\t", __FUNCTION__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
}
#define FILE(filename) { \
freopen(#filename ".in", "r", stdin); \
freopen(#filename ".out", "w", stdout); \
}
#define All(x) x.begin(), x.end()
#define rAll(x) x.rbegin(), x.rend()
#define pii pair<int, int>
#define fi first
#define se second
#define i64 long long
#define mkp make_pair
// #define int long long
#define epb emplace_back
using namespace std;
const int _N = 1e6 + 5, mod = 1e9 + 7, inf = 1e9;
template<typename T> void Max(T &x, T y) {x = max(x, y);}
template<typename T> void Min(T &x, T y) {x = min(x, y);}
template<typename T1, typename T2>
void Addmod(T1 &x, T2 y) {x += y; x >= mod ? x -= mod : x;}
template<typename T1, typename T2>
T1 Add(T1 x, T2 y) {x += y; return x >= mod ? x - mod : x;}
namespace BakaCirno {
void _() {
}
}
signed main() {
// FILE(test);
cin.tie(0)->sync_with_stdio(0); int T = 1;
// cin >> T;
while (T--) BakaCirno::_();
}
计算几何
struct Vec {
double x, y;
Vec(double x = 0, double y = 0) : x(x), y(y) {}
Vec operator + (const Vec &A) const {return Vec(x + A.x, y + A.y);}
Vec operator - (const Vec &A) const {return Vec(x - A.x, y - A.y);}
Vec operator * (const double &k) const {return Vec(x * k, y * k);}
Vec operator / (const double &k) const {return Vec(x / k, y / k);}
double operator * (const Vec &A) const {return x * A.y - y * A.x;}
double operator () () const {return hypot(x, y);}
Vec Turn90() const {return Vec(y, -x);}
Vec Turn(const double &angle) const
{return Vec(x * cos(angle) - y * sin(angle), y * cos(angle) + x * sin(angle));}
};
struct Line {
Vec poi, vec;
Line(Vec poi = Vec(), Vec vec = Vec()) : poi(poi), vec(vec) {}
Vec operator * (const Line &B) const {
const Line &A = *this;
return A.poi + A.vec * ((B.poi - A.poi) * B.vec / (A.vec * B.vec));
}
};
struct Circle {
Vec poi; double R;
Circle(Vec poi = Vec(), double R = 0) : poi(poi), R(R) {}
Circle(Vec A, Vec B, Vec C) {
Line ln1((A + B) / 2, (B - A).Turn90());
Line ln2((B + C) / 2, (C - B).Turn90());
poi = ln1 * ln2, R = (A - poi)();
}
bool ChkIn(const Vec &A) const {return (A - poi)() <= R;}
};
向量,直线交点,已知三点求圆。
NTT
template<int g, int mod>
struct NTT {
int lim, tim;
vector<int> rev;
int Qpow(int x, int y) {
int res = 1; x %= mod;
for (; y; y >>= 1, x = 1ll * x * x % mod)
if (y & 1) res = 1ll * res * x % mod;
return res;
}
void Init(int up) {
for (lim = 1, tim = 0; lim < up; lim <<= 1, ++tim);
rev.resize(lim);
for (int i = 1; i < lim; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (tim - 1));
}
void do_NTT(vector<int> &A) {
A.resize(lim);
for (int i = 1; i < lim; ++i)
if (i < rev[i]) swap(A[i], A[rev[i]]);
int A0, A1;
for (int i = 1; i < lim; i <<= 1) {
const int w = Qpow(g, (mod - 1) / (i << 1));
for (int j = 0; j < lim; j += i << 1)
for (int k = 0, W = 1; k < i; ++k, W = 1ll * w * W % mod) {
A0 = (A[j + k] + 1ll * A[j + k + i] * W % mod) % mod;
A1 = (A[j + k] - 1ll * A[j + k + i] * W % mod) % mod;
A[j + k] = A0, A[j + k + i] = A1;
}
}
}
void do_INTT(vector<int> &A) {
do_NTT(A), reverse(A.begin() + 1, A.end());
const int inv = Qpow(lim, mod - 2);
for (int i = 0; i < lim; ++i) {
if (A[i] < 0) A[i] += mod;
A[i] = 1ll * A[i] * inv % mod;
}
}
};
struct Poly {
static const int g = 3, mod = 998244353, inv2 = 499122177;
vector<int> A, C, lnB, invB;
NTT<g, mod> ntt;
Poly(int deg = 0) : A(vector<int>(deg, 0)) {}
Poly(const vector<int> A) : A(A) {}
Poly operator * (Poly ano) {
int deg = A.size() + ano.A.size() - 1;
ntt.Init(A.size() + ano.A.size());
ntt.do_NTT(A), ntt.do_NTT(ano.A);
Poly res(ntt.lim);
for (int i = 0; i < ntt.lim; ++i)
res.A[i] = 1ll * A[i] * ano.A[i] % mod;
ntt.do_INTT(res.A);
res.A.resize(deg);
return res;
}
void getInv(int deg, vector<int> &A, vector<int> &B) {
if (deg == 1) {
B[0] = ntt.Qpow(A[0], mod - 2);
return ;
}
getInv((deg + 1) >> 1, A, B);
ntt.Init((deg + 1) << 1);
C.resize(ntt.lim);
copy(A.begin(), A.begin() + deg, C.begin());
fill(C.begin() + deg, C.begin() + ntt.lim, 0);
ntt.do_NTT(C), ntt.do_NTT(B);
for (int i = 0; i < ntt.lim; ++i)
B[i] = 1ll * (2 - 1ll * C[i] * B[i] % mod + mod) % mod * B[i] % mod;
ntt.do_INTT(B);
fill(B.begin() + deg, B.begin() + ntt.lim, 0);
}
Poly inv() {
vector<int> A = this->A, B;
int deg = A.size();
ntt.Init((deg + 1) << 1);
A.resize(ntt.lim), B.resize(ntt.lim);
getInv(deg, A, B);
B.resize(deg);
return Poly(B);
}
int &operator[] (const int &index) {return A[index];}
Poly deriv() {
Poly res(A.size() - 1);
for (int i = 1; i < (int)A.size(); ++i)
res[i - 1] = 1ll * A[i] * i % mod;
return res;
}
Poly integ() {
Poly res(A.size() + 1);
for (int i = 1; i <= (int)A.size(); ++i)
res[i] = 1ll * A[i - 1] * ntt.Qpow(i, mod - 2) % mod;
res[0] = 0;
return res;
}
Poly ln() {return (this->deriv() * this->inv()).integ();}
void getExp(int deg, vector<int> &A, vector<int> &B) {
if (deg == 1) {
B[0] = 1;
return ;
}
getExp((deg + 1) >> 1, A, B);
B.resize(deg);
lnB = Poly(B).ln().A;
ntt.Init((deg + 1) << 1);
C.resize(ntt.lim);
copy(A.begin(), A.begin() + deg, C.begin());
for (int i = 0; i < deg; ++i)
C[i] = (C[i] - lnB[i] + mod) % mod;
++C[0];
fill(C.begin() + deg, C.begin() + ntt.lim, 0);
ntt.do_NTT(B), ntt.do_NTT(C);
for (int i = 0; i < ntt.lim; ++i)
B[i] = 1ll * B[i] * C[i] % mod;
ntt.do_INTT(B);
fill(B.begin() + deg, B.begin() + ntt.lim, 0);
}
Poly exp() {
vector<int> A = this->A, B;
int deg = A.size();
ntt.Init((deg + 1) << 1);
A.resize(ntt.lim), B.resize(ntt.lim);
getExp(deg, A, B);
B.resize(deg);
return Poly(B);
}
void getSqrt(int deg, vector<int> &A, vector<int> &B) {
if (deg == 1) {
B[0] = 1;
return ;
}
getSqrt((deg + 1) >> 1, A, B);
ntt.Init((deg + 1) << 1);
fill(invB.begin(), invB.begin() + ntt.lim, 0);
getInv(deg, B, invB);
C.resize(ntt.lim);
copy(A.begin(), A.begin() + deg, C.begin());
fill(C.begin() + deg, C.begin() + ntt.lim, 0);
ntt.do_NTT(C), ntt.do_NTT(invB), ntt.do_NTT(B);
for (int i = 0; i < ntt.lim; ++i)
B[i] = (1ll * B[i] * inv2 % mod + 1ll * C[i] * invB[i] % mod * inv2 % mod) % mod;
ntt.do_INTT(B);
fill(B.begin() + deg, B.begin() + ntt.lim, 0);
}
Poly sqrt() {
vector<int> A = this->A, B;
int deg = A.size();
ntt.Init((deg + 1) << 1);
A.resize(ntt.lim), B.resize(ntt.lim), invB.resize(ntt.lim);
getSqrt(deg, A, B);
B.resize(deg);
return Poly(B);
}
};
Poly
内重载了 operator *
。
随手写的 Format 输出
namespace fmt {
constexpr void fmt(ostream &out, const char* str) {
for (const char* i = str; *i != '\0'; ++i) {
if (*i == '{' || *i == '}') throw "Syntax Error";
out << *i;
}
}
template<typename T>
constexpr void fmt(ostream &out, const char* str, const T arg) {
for (const char* i = str; *i != '\0'; ++i) {
if ((*i == '{' && *(i + 1) != '}') || *i == '}') throw "Syntax Error";
if (*i == '{') {out << arg; fmt(out, i + 2); break;}
out << *i;
}
}
template<typename T, typename ...Args>
constexpr void fmt(ostream &out, const char* str, const T arg, const Args ...args) {
for (const char* i = str; *i != '\0'; ++i) {
if ((*i == '{' && *(i + 1) != '}') || *i == '}') throw "Syntax Error";
if (*i == '{') {out << arg; fmt(out, i + 2, args...); break;}
out << *i;
}
}
template<typename ...Args>
constexpr inline void fmtout(const Args ...args) {fmt(cout, args...);}
template<typename ...Args>
constexpr inline void fmterr(const Args ...args) {fmt(cerr, args...);}
}
仅支持了最简单的 format
输出。