# 龙珠

#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;
}


# 少抢了多少红包

#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;
}
`

06-22

07-16 51
07-21 1005
08-17 167
08-06 110
02-19
02-26 27