宁波市多校训练(五)


龙珠

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, Q;
string op;

int fa[N], sz[N], cnt[N];

int find(int x) {
    if (x != fa[x]) {
        int f = fa[x];
        fa[x] = find(fa[x]);
        //带权并查集
        cnt[x] += cnt[f]; // 在并查集里修改儿子节点的值 先更新父节点的值 然后再更新儿子的值
    }
    return fa[x];
}

void Union(int a, int b) { // a->b
    a = find(a);
    b = find(b);
    if (a == b) return;

    sz[b] += sz[a];
    sz[a] = 0;
    cnt[a]++;

    fa[a] = b;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int T, a, b;
    cin >> T;
    for (int cs = 1; cs <= T; cs++) {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            fa[i] = i;
            sz[i] = 1;
            cnt[i] = 0;
        }

        printf("Case %d:\n", cs);

        cin >> Q;
        while (Q--) {
            cin >> op;
            if (op == "T") {
                cin >> a >> b;
                Union(a, b);

            } else {
                cin >> a;
                find(a);
                printf("%d %d %d\n", fa[find(a)], sz[find(a)], cnt[a]);

            }
        }
    }

    return 0;
}

少抢了多少红包

啊……数组越界 dp[-1] 返回的居然是 wa

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int n, m, k;
ll cnt[N][15];
ll dp[N][15];

ll Max(ll a, ll b, ll c) {
    return max(max(a, b), c);
}

int main() {
    ios::sync_with_stdio(false);
    while (2 == scanf("%d%d", &n, &m)) {
        if (!n && !m) break;
        int Mx = 0;
        memset(cnt, 0, sizeof cnt);

        for (int i = 1, a, b; i <= n; i++) {
            scanf("%d%d", &a, &b);
            Mx = max(Mx, b);
            cnt[b][a]++;
        }

        memset(dp, 0, sizeof dp);
        dp[0][5] = Max(cnt[0][4], cnt[0][5], cnt[0][6]);
        for (int i = 1; i <= Mx; i++) {
            if (i <= 4) {
                for (int j = 5 - i; j <= 5 + i; j++) {
                    dp[i][j] = Max(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]) +
                               Max(cnt[i][j - 1], cnt[i][j], cnt[i][j + 1]);
                }
            } else {
                for (int j = 1; j <= 10; j++) {
                    dp[i][j] = Max(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]) +
                               Max(cnt[i][j - 1], cnt[i][j], cnt[i][j + 1]);
                }
            }
        }

        ll res = m;
        for (int i = 1; i <= 10; i++) {
            res = max(res, dp[Mx][i]);
        }
        printf("%lld\n", res - m);
    }

    return 0;
}

小伙子找姑娘 · 扩展卢卡斯

模意义下的 合数+错排
可惜 模数他妈的居然不是质数 ヽ(´¬`)ノ

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
namespace ExLucas {
//扩展卢卡斯
    inline ll qpow(ll a, ll b, ll p = LLONG_MAX) {
        a %= p;
        ll res = 1;
        while (b) {
            if (b & 1) res = res * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return res;
    }


    ll fac(ll n, ll p, ll pk) {//  计算 n!/p (mod p^k)  pk表示p^k
        if (!n) return 1;
        ll res = 1;
        for (ll i = 2; i <= pk; i++) {
            if (i % p)
                res = res * i % pk;
        }
        res = qpow(res, n / pk, pk);

        ll lim = n % pk;
        for (ll i = 2; i <= lim; i++) {
            if (i % p)
                res = res * i % pk;
        }
        return res * fac(n / p, p, pk) % pk;
    }

    ll Exgcd(ll a, ll b, ll &x, ll &y) { // 计算 ax+by=gcd(a,b)
        if (!b) {
            x = 1;
            y = 0;
            return a;
        }
        ll g = Exgcd(b, a % b, x, y);
        ll d = x;
        x = y;
        y = d - a / b * y;
        return g;
    }

    ll Inv(ll a, ll p) { // 计算 ax ≡ 1 mod p  前提a、p互质
        ll x, y;
        Exgcd(a, p, x, y);
        return (x % p + p) % p;
    }

    // 计算 C(n,m) mod p^k 其中 C(n,m)与p^k之间有相同的因子 p
    // 有相同的因子 说明 n! or m! or (n-m)!有一个在 mod p下会变为0 需要将p提取出来
    ll C(ll n, ll m, ll p, ll pk) {
        if (n < m) return 0;
        ll f1 = fac(n, p, pk);
        ll f2 = fac(m, p, pk);
        ll f3 = fac(n - m, p, pk);

        // 分解因子p 统计分解出了cnt个p 最后再乘回来 p^(k1-k2-k3)
        ll cnt = 0;// cnt= k1-k2-k3
        for (ll i = n; i; i /= p) {
            cnt += i / p;
        }
        for (ll i = m; i; i /= p) {
            cnt -= i / p;
        }
        for (ll i = n - m; i; i /= p) {
            cnt -= i / p;
        }

        return f1 * Inv(f2, pk) % pk * Inv(f3, pk) % pk * qpow(p, cnt, pk) % pk;
    }


    ll a[N]; // 保存C(n,m)与p有相同因子时的模后答案
    ll prime[N];//保存所有因子p
    ll c[N];// 保存 p^k
    int tot = 0;

    // 中国剩余定理
    // x满足所有等式 x ≡ a[i] mod m[i] 返回符合要求的 x
    //  a[] 模后答案   m[] 模数数组
    inline ll CRT(ll a[], ll m[], int n) {
        ll M = 1, res = 0;
        for (int i = 1; i <= n; ++i) M *= m[i];
        for (int i = 1; i <= n; ++i) {
            ll Mi = M / m[i];
            res = (res + a[i] * Inv(Mi, m[i]) % M * Mi % M) % M;

            //有时候res可能是负的 所以还需要 +M
        }
        return res;
    }

	
	// 当模数固定时 先预处理 
    void init_mod(ll p) {
        //先预处理模数
        for (ll i = 2; p > 1 && i * i <= p; i++) {
            if (p % i == 0) {
                ll pk = 1; // pk表示p^k
                while (p % i == 0) {
                    p /= i;
                    pk *= i;
                }
                prime[++tot] = i;
                c[tot] = pk;
            }
        }
        if (p > 1) {
            prime[++tot] = p;
            c[tot] = p;
        }
    }


    ll Exlucas(const ll n, const ll m, ll p) {
        for (int i = 1; i <= tot; i++) {
            a[i] = C(n, m, prime[i], c[i]);
        }
        return CRT(a, c, tot) % p;
    }

    void init() {
        tot = 0;
    }

}
using namespace ExLucas;

ll f[N], p = 956452433;

int main() {
    ios::sync_with_stdio(false);

    //错排公式 f[n]=(n-1)*(f[n-1]+f[n-2]) f[0]=f[1]=1
    f[2] = 1;
    for (int i = 3; i <= 500000; i++) {
        f[i] = ((f[i - 1] + f[i - 2]) % p) * (i - 1) % p;
    }
    f[0] = 1;//特殊处理

    init_mod(p);

    ll n, m;
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%lld%lld", &n, &m);
        ll res = Exlucas(n, m, p);

        res = res * f[n - m] % p;
        printf("%lld\n", res);
    }

    return 0;
}

俞巨的草坪

多边形内核 + 判断点是否在内核上

代码参考算法竞赛入门到进阶

#include <bits/stdc++.h>
using namespace std;
int n, m, k;

namespace Polygon {
    const double eps = 1e-8;

    int sgn(double x) {
        if (fabs(x) < eps) return 0;
        else return x < 0 ? -1 : 1;
    }
    //判断x是否等于0

    struct Point {
        double x, y;

        Point() {}

        Point(double x, double y) : x(x), y(y) {}

        void input() { scanf("%lf%lf", &x, &y); }//输入
        void output() { printf("%.2f %.2f\n", x, y); } //输出

        //向量的运算操作
        Point operator+(Point B) { return Point(x + B.x, y + B.y); }

        Point operator-(Point B) { return Point(x - B.x, y - B.y); }

        Point operator*(double k) { return Point(x * k, y * k); }

        Point operator/(double k) { return Point(x / k, y / k); }

        bool operator==(Point B) { return sgn(x - B.x) == 0 && sgn(y - B.y) == 0; }

        double operator^(const Point &b) const { return x * b.y - y * b.x; }

        //叉积
        double operator*(const Point &b) const { return x * b.x + y * b.y; }
        //点积
    };//二维 点
    typedef Point Vector;
    // Vector : OA-OB=BA

    double Cross(Vector A, Vector B) {
        return A.x * B.y - A.y * B.x;
    }
    //AXB的叉积 注意 叉积有顺序的
    //AXB>0 B在A的逆时针方向
    //AXB<0 B在A的顺时针方向
    //AXB=0 B与A共线,可能是同方向的 也可能是反方向的


    struct Line {
        Point s, e;
        Vector v;
        double ang;

        Line() {};

        Line(Point s1, Point e1) : s(s1), e(e1) {
            v = e1 - s1;
            ang = atan2(v.y, v.x);
        }

        bool operator<(const Line &L) const {
            return ang < L.ang;
        }//用于极角排序

        bool point_on_seg(Point p) {
            return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
        }

    };

    typedef Line Seg;

    //点p在直线L的左边 用于找内核
    bool OnLeft(Line L, Point p) {
        return sgn(Cross(L.v, p - L.s)) > 0;
    }

    // 计算两直线的交点
    Point Cross_point(Line a, Line b) {
        Vector u = a.s - b.s;
        double t = Cross(b.v, u) / Cross(a.v, b.v);
        return a.s + a.v * t;
    }

    // 求半平面交 返回凸边形
    // O(nlogn)
    // 其中 vector<Line> L有特殊要求 逆时针形成环 使得内核在向量的左侧肯定存在
    // 产生内核的点的排列 也是逆时针的
    vector<Point> HPI(vector<Line> L) {
        int sz = L.size();
        sort(L.begin(), L.end());//将所有的半平面按照极角排序
        int first, last;//指向双端队列首尾元素
        vector<Point> p(sz);//两个相邻半平面的焦点
        vector<Line> q(sz);//模拟双端队列
        vector<Point> res;//半平面交形成的凸包

        q[first = last = 0] = L[0];
        for (int i = 1; i < sz; i++) {
            //情况1 L[i]覆盖原队尾:删除尾元素 的半平面
            while (first < last && !OnLeft(L[i], p[last - 1])) last--;
            //情况2 L[i]覆盖原队首:删除首元素的半平面
            while (first < last && !OnLeft(L[i], p[first])) first++;
            q[++last] = L[i];//将当前的半平面加入双端队列的队尾

            //极角相同的两个半平面保留左边的那个
            if (fabs(Cross(q[last].v, q[last - 1].v)) < eps) {//平行
                last--;
                if (OnLeft(q[last], L[i].s)) q[last] = L[i];
            }

            //计算队尾无用的半平面
            if (first < last) p[last - 1] = Cross_point(q[last - 1], q[last]);
        }

        //情况3 L[i]不能加入到队列: 删除队列首尾无用的半平面
        while (first < last && !OnLeft(q[first], p[last - 1])) last--;
        if (last == first) {
            //内核是一个点
            res.push_back(p[0]);
            return res;
        }
        if (last - first < 0) return res;//空集
        p[last] = Cross_point(q[last], q[first]);//计算队列首尾的交点
        for (int i = first; i <= last; i++) {
            res.push_back(p[i]);//复制答案
        }
        return res;
    }

    //判断点是否在半平面交的内核上
    int isInHPI(Point p, vector<Point> polygon) {
        int sz = polygon.size();
        for (int i = 0; i < sz; i++) {
            if (p == polygon[i]) return 3;//点在多边形的顶点上
        }

        for (int i = 0; i < sz; i++) {
            Seg L = Seg(polygon[i], polygon[(i + 1) % sz]);
            if (L.point_on_seg(p)) {
                return 2;//点在多边形的边上
            }
        }

        int cnt = 0;
        for (int i = 0; i < sz; i++) {
            int j = (i + 1) % sz;
            int c = sgn(Cross(p - polygon[j], polygon[i] - polygon[j]));
            int u = sgn(polygon[i].y - p.y);
            int v = sgn(polygon[j].y - p.y);
            if (c > 0 && u < 0 && v >= 0) cnt++;
            if (c < 0 && u >= 0 && v < 0) cnt--;
        }
        return cnt != 0; // 1在内部 0 在外部
    }

}
using namespace Polygon;
Polygon::Point p[2005], o;

vector<Line> L;
vector<Point> polygon;//内核

int main() {
    ios::sync_with_stdio(false);

    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);

        L.clear();
        for (int i = 1; i <= n; i++) {
            p[i].input();

        }

        L.push_back({p[1], p[n]});
        for (int i = n; i > 1; i--) {
            L.push_back({p[i], p[i - 1]});
        }

        //半平面交求内核
        polygon = Polygon::HPI(L);

        scanf("%d", &m);
        while (m--) {
            o.input();
            if (isInHPI(o, polygon)) {
                puts("YES");
            } else {
                puts("NO");
            }
        }
    }

    return 0;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页