【ZJSU - 大红大紫:ACM - Template】比赛用模板06:多项式与几何
作者:互联网
多项式与几何
快速数论变换 \(\tt NTT\)
\(\mathcal O(N * logN)\) 。
namespace poly{
const int M = 998244353,G = 3,Gi = 332748118;
const int N = 5000000;
int n,m;
int res,ans[5000005];
int limit = 1;
int L;
int RR[5000005];
LL a[N],b[N];
LL ps(LL n,LL k){
LL res = 1;
while(k){
if (k & 1) res = res * n % M;
n = n * n % M;
k >>= 1;
}
return res;
}
LL inv(LL x){return ps(x,M - 2);}
void NTT(LL *A ,int type){
for(int i = 0; i < limit; i++){
if (i < RR[i]){
swap(A[i],A[RR[i]]);
}
}
for(int mid = 1; mid < limit; mid <<= 1){
LL wn = ps(G,(M - 1) / (mid * 2));
if (type == -1){
wn = ps(wn,M - 2);
}
for(int len = mid << 1,pos = 0; pos < limit; pos += len){
LL w = 1;
for(int k = 0; k < mid ; ++k,w = (w * wn) % M){
int x = A[pos + k],y = w * A[pos + mid + k] % M;
A[pos + k] = (x + y) % M;
A[pos + k + mid] = (x -y + M) % M;
}
}
}
if (type == -1){
LL limit_inv = inv(limit);
for(int i = 0; i < limit; i++){
A[i] = (A[i] * limit_inv) % M;
}
}
}
void poly_mul(LL *a,LL *b,int deg){
for(limit = 1, L = 0; limit <= deg; limit <<= 1)L ++;
for(int i = 0; i < limit ; i++){
RR[i] = (RR[i >> 1] >> 1) | ((i & 1) << (L - 1));
}
NTT(a,1);
NTT(b,1);
for(int i = 0; i < limit; i++){
a[i] = a[i] * b[i] % M;
}
NTT(a,-1);
}
}
using namespace poly;
int main(){
cin >> n >> m;
for(int i = 0; i <= n; i++){
cin >> a[i];
}
for(int i = 0; i <= m; i++){
cin >> b[i];
}
poly_mul(a,b,n+m);
for(int i = 0; i <= n + m; i++){
cout << a[i] << " \n"[i == n + m];
}
return 0;
}
凸包、二维凸包与旋转卡壳
\(\mathcal{Provided \ by \ \pmb{Wcj}}\) 。
struct fff { double x, y; } p[maxn], ans[maxn], p0;
double d(fff p1, fff p2) { // 距离公式
return sqrt((p2.y - p1.y) * (p2.y - p1.y) + (p2.x - p1.x) * (p2.x - p1.x));
}
LL dd(fff p1, fff p2) { // 距离公式
return (p2.y - p1.y) * (p2.y - p1.y) + (p2.x - p1.x) * (p2.x - p1.x);
}
double check(fff a1, fff a2, fff b1, fff b2) { // 叉积
return (a2.x - a1.x) * (b2.y - b1.y) - (b2.x - b1.x) * (a2.y - a1.y);
}
inline bool cmp(fff a, fff b) {
double A = atan2(a.y - p0.y, a.x - p0.x);
double B = atan2(b.y - p0.y, b.x - p0.x);
if (A != B) return A < B;
else if (a.x == b.x) return a.y < b.y;
else return a.x < b.x;
}
inline long long chaji(int x1, int y1, int x2, int y2) {
return (1LL * x1 * y2 - 1LL * x2 * y1);
}
inline long long fx(fff a, fff b, fff c) {
return chaji((b.x - a.x), (b.y - a.y), (c.x - a.x), (c.y - a.y));
}
inline void Find() // 二维凸包
{
p0 = (fff){INF, INF};
int k = 0;
for (int i = 0; i < n; ++i)
if (p0.y > p[i].y || (p0.y == p[i].y && p0.x > p[i].x))
p0 = p[i], k = i;
swap(p[k], p[0]);
sort(&p[1], &p[n], cmp);
ans[0] = p[0], ans[1] = p[1], top = 1;
for (int i = 2; i < n;) {
if (top && fx(ans[top - 1], p[i], ans[top]) >= 0) top--;
else ans[++top] = p[i++];
}
}
int get() { //旋转卡壳
LL c = 0;
if (top == 1) return dd(ans[0], ans[1]);
ans[++ top] = ans[0];
int j = 2;
for (int i = 0; i < top; ++i) {
while (fx(ans[i], ans[i + 1], ans[j]) < fx(ans[i], ans[i + 1], ans[j + 1]))
j = (j + 1) % top;
c = max(c, max(dd(ans[i], ans[j]), dd(ans[i + 1], ans[j])));
}
return c;
}
封装待更新(参考杭电第八场1010)
判断线段是否相交:快速排斥+跨立实验
struct Node { int x, y; } a, b, c, d;
bool judge(Node a, Node b, Node c, Node d) {
if (!(min(a.x, b.x) <= max(c.x, d.x) && min(c.x, d.x) <= max(a.x, b.x) &&
min(a.y, b.y) <= max(c.y, d.y) && min(c.y, d.y) <= max(a.y, b.y)))
return false;//快速排斥
double u, v, w, z;//跨立实验
u = (c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y); // AC×AB
v = (d.x - a.x) * (b.y - a.y) - (b.x - a.x) * (d.y - a.y); // AD×AB
w = (a.x - c.x) * (d.y - c.y) - (d.x - c.x) * (a.y - c.y); // CA×AB
z = (b.x - c.x) * (d.y - c.y) - (d.x - c.x) * (b.y - c.y); // CB×AB
if (u * v <= 1e-9 && w * z <= 1e-9) return true;
return false;
}
int main() {
int t;
cin >> t;
while (t--) {
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> d.x >> d.y;
if (judge(a, b, c, d)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
标签:p2,06,int,大红大紫,top,ZJSU,return,ans,fff 来源: https://www.cnblogs.com/WIDA/p/16676286.html