Avian Darts

# Distinct Sub-palindromes

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll mod = 998244353;

ll qpow(ll a, ll b) {
a %= mod;
ll res = 1;
while (b) {
if (b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}

ll n;
ll Cn3 = (24 * 25 * 26) % mod;// C(n,3)

int main() {

int T;
cin >> T;
while (T--) {
cin >> n;
if (n <= 3)
cout << qpow(26, n) << endl;
else
cout << Cn3 << endl;
}
return 0;
}


# Fibonacci Sum

F ( n ) = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] F(n)=\frac{1}{\sqrt 5}\bigg[ \bigg( \frac{1+\sqrt 5}{2} \bigg)^n- \bigg( \frac{1-\sqrt 5}{2} \bigg)^n \bigg]

F ( n ) k = ( 1 5 ) k [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] k F(n)^k=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[ \bigg( \frac{1+\sqrt 5}{2} \bigg)^n- \bigg( \frac{1-\sqrt 5}{2} \bigg)^n \bigg]^k

b = ( 1 − 5 2 ) n b=\bigg( \frac{1-\sqrt 5}{2} \bigg)^n

[ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] k = ( a n − b n ) k \bigg[ \bigg( \frac{1+\sqrt 5}{2} \bigg)^n- \bigg( \frac{1-\sqrt 5}{2} \bigg)^n \bigg]^k=(a^n-b^n)^k

( a n − b n ) k = C k 0 ( a n ) 0 ( − b n ) k + C k 1 ( a n ) 1 ( − b n ) k − 1 + . . . . . + C k k ( a n ) k ( − b n ) 0 = ∑ i = 0 k ( − 1 ) k − i ( a n ) i ( b n ) k − i (a^n-b^n)^k=C^0_k(a^n)^0(-b^n)^k+C^1_k(a^n)^1(-b^n)^{k-1}+.....+C^k_k(a^n)^k(-b^n)^0\\=\sum^k_{i=0}(-1)^{k-i}(a^n)^i(b^n)^{k-i}

F ( n ) k = ( 1 5 ) k [ ∑ i = 0 k ( − 1 ) k − i C k i ( a n ) i ( b n ) k − i ] F(n)^k=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[\sum^k_{i=0}(-1)^{k-i}C^i_k(a^n)^i(b^n)^{k-i}\bigg]

F ( c ) k = ( 1 5 ) k [ ∑ i = 0 k ( − 1 ) k − i C k i ( a c ) i ( b c ) k − i ] F(c)^k=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[\sum^k_{i=0}(-1)^{k-i}C^i_k(a^c)^i(b^c)^{k-i}\bigg]

F ( 2 c ) k = ( 1 5 ) k [ ( 1 + 5 2 ) 2 c − ( 1 − 5 2 ) 2 c ] k = ( 1 5 ) k [ ∑ i = 0 k ( − 1 ) k − i C k i ( a 2 c ) i ( b 2 c ) k − i ] = ( 1 5 ) k [ ∑ i = 0 k ( − 1 ) k − i C k i ( ( a c ) i ( b c ) k − i ) 2 ] F(2c)^k=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[ \bigg( \frac{1+\sqrt 5}{2} \bigg)^{2c}- \bigg( \frac{1-\sqrt 5}{2} \bigg)^{2c} \bigg]^k\\=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[\sum^k_{i=0}(-1)^{k-i}C^i_k(a^{2c})^i(b^{2c})^{k-i}\bigg]\\=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[\sum^k_{i=0}(-1)^{k-i}C^i_k\bigg((a^{c})^i(b^{c})^{k-i}\bigg)^2\bigg]

F ( n c ) k = ( 1 5 ) k [ ∑ i = 0 k ( − 1 ) k − i C k i ( ( a c ) i ( b c ) k − i ) n ] F(nc)^k=\bigg( \frac{1}{\sqrt 5} \bigg)^k\bigg[\sum^k_{i=0}(-1)^{k-i}C^i_k\bigg((a^{c})^i(b^{c})^{k-i}\bigg)^n\bigg]

S ( n ) = a 1 × q n − 1 q − 1 S(n)=a_1\times\frac{q^n-1}{q-1}

1 5 \cfrac{1}{\sqrt 5} 在模意义下需要借助 二次剩余 来求，即 x 2 = 5 m o d    1 0 9 + 9 x^2=5\mod {10^9+9}

a = 1 + 5 2 = 691504013 b = 1 − 5 2 = 308495997 1 5 = 276601605 a= \frac{1+\sqrt 5}{2} =691504013\\b= \frac{1-\sqrt 5}{2} =308495997\\\frac{1}{\sqrt 5}=276601605

a b m o d    p = a b m o d    φ ( p ) + φ ( p ) m o d    p a^b \mod p=a^{b \mod \varphi(p)+\varphi(p)}\mod p

φ ( 1 0 9 + 9 ) = 1 0 9 + 8 \varphi(10^9+9)=10^9+8

ps:如果还T的话，scanf改cin、关掉一两个数组，你就可以过去了……

// 赛后ac代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 9;
const int N = 1e5 + 10;

ll qpow(ll a, ll b) {
a %= mod;
ll res = 1;
while (b) {
if (b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}

ll Phi = mod - 1;//欧拉降幂

ll euler(ll a, ll b) {
return qpow(a, ((b % Phi) + Phi));
}

ll fac[N], inv[N];
void init(int n) {
fac[0] = inv[0] = 1;
for (int i = 1; i <= n; ++i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = inv[i - 1] * qpow(i, mod - 2) % mod;
}
}

ll C(int n, int m) {
if (n < m || m < 0)return 0;
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

ll Add(ll x, ll y) {
if (x < 0)x += mod;
if (y < 0) y += mod;
return (x + y) % mod;
}

ll Mul(ll x, ll y) {
x %= mod;
y %= mod;
return x * y % mod;
}

ll n, c;
int k;
ll a = 691504013;// (1+sqrt(5))/2
ll b = 308495997;// (1-sqrt(5))/2
ll Inv5 = 276601605;// 1/sqrt(5)

ll A, B, A_B, q;

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

init(100000);

int T;
cin >> T;
while (T--) {
cin >> n >> c >> k;
A = qpow(a, c);// a^c
B = qpow(b, c);// b^c
A_B = Mul(A, qpow(B, mod - 2));// A/B
q = qpow(B, k);//公比

ll res = 0, tmp;
for (int i = 0; i <= k; i++) {
//if (q == 0)continue; mod为质数 永远不会有公比为0的时候
if (q == 1) {
tmp = n % mod;
} else {
tmp = Mul(Mul(Add(euler(q, n), mod - 1), qpow(Add(q, mod - 1), mod - 2)), q);
}
tmp = Mul((C(k, i) * ((k - i) & 1 ? -1 : 1)), tmp);
q = Mul(q, A_B);
}
res = Mul(res, qpow(Inv5, k));
cout << res << endl;

}
return 0;
}


# Finding a MEX

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 3;

vector<int> e[N], E[N];
int vis[N];
int a[N];
int u[N], v[N], d[N];
int n, m;

struct segTree {
#define ls (o<<1)
#define rs (o<<1|1)

struct node {
int l, r;
int sum;
} t[N << 2];

int cnt[N];

void pushup(int o) {
t[o].sum = t[ls].sum + t[rs].sum;
}

//不带数组 建树
void build(int o, int l, int r) {
t[o].l = l;
t[o].r = r;
t[o].sum = 0;
if (l == r) {
cnt[l] = 0;
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}

int query(int o) {
if (t[o].l == t[o].r) {
return t[o].l;
}
int len = t[o].r - t[o].l + 1;
if (t[ls].sum >= (len - (len >> 1)))
return query(rs);
else return query(ls);
}

void add(int o, int pos, int val) {
if (t[o].l == t[o].r) {
cnt[t[o].l] += val;

if (cnt[t[o].l] > 0)
t[o].sum = 1;
else
t[o].sum = 0;
return;
}
int mid = t[o].l + t[o].r >> 1;
if (pos <= mid) add(ls, pos, val);
pushup(o);
}

} ST[351];

int id[N], dfn = 0;
int Hash[N];

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

int T;
cin >> T;
while (T--) {
cin >> n >> m;

//init
dfn = 0;
for (int i = 1; i <= n; i++) {
e[i].clear();//所有边
E[i].clear();//大点连边
vis[i] = d[i] = 0;
id[i] = 0;
}

for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i]++;//在原来的基础上+1 便于线段树维护
}

for (int i = 1; i <= m; i++) {
cin >> u[i] >> v[i];
e[u[i]].push_back(v[i]);
e[v[i]].push_back(u[i]);

d[u[i]]++;
d[v[i]]++;
}

int block = 1000;

for (int i = 1; i <= n; i++) {
// 区分 部分度数超过block的点为大点 没有超过的为小点
if (d[i] > block) {
vis[i] = 1; // 标记大点
}
}

for (int i = 1; i <= m; i++) {
if (vis[v[i]]) // 当v[i]是大点时 需要对v[i]建线段树 如果u[i]要修改权值 则v[i]对应的线段树也要修改
E[u[i]].push_back(v[i]);

if (vis[u[i]])
E[v[i]].push_back(u[i]);
}

for (int i = 1; i <= n; i++) {
if (vis[i]) {
id[i] = ++dfn; // 记录点i对应的是哪颗线段树
ST[dfn].build(1, 1, d[i] + 1);
for (int j : e[i]) {
if (a[j] <= d[i])
}
}
}

int q, op, x, y;
cin >> q;
while (q--) {
cin >> op;
if (op == 1) {
//将 a[x]修改成y
cin >> x >> y;
y++;
for (int z:E[x]) {
if (vis[z]) { // 如果相连的是大点
if (a[x] <= d[z])
if (y <= d[z]) // 如果y值比点z的度数还大 显然y不可能是F(z)的答案
}
}
a[x] = y;

} else { //op=2
cin >> x;
if (vis[x]) {
cout << ST[id[x]].query(1) - 1 << endl;
} else {
// 用set会t
for (int i = 1; i <= d[x]; i++)
Hash[i] = 0;

for (int z:e[x]) {
if (a[z] > d[x])continue;
Hash[a[z]] = 1;
}
int res = 1;
for (int i = 1; i <= d[x]; i++)
if (!Hash[i]) {
res = i;
break;
}

cout << res - 1 << endl;
}
}
}
}

return 0;
}


Hunting Monsters
Integral Calculus

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const int N = 1e6 + 10;
int n;

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

struct Line {
// y=kx+b
ll k, b;

bool operator==(const Line line) const {
return k == line.k && b == line.b;
}

bool operator<(const Line line) const {
if (b == line.b) {
return k < line.k;
}
return b > line.b;
}
} L[N];

int Stack[N], top = 0;

int check(Line l1, Line l2, Line l3) {
double x1 = (double) (l2.b - l1.b) / (double) (l1.k - l2.k); // 第一和第二的交点
double x2 = (double) (l3.b - l2.b) / (double) (l2.k - l3.k); // 新的直线和第二的交点
if (sgn(x1 - x2) > 0) {
return 1;
} else if (sgn(x1 - x2) == 0) {
return 2;
}
return 3;
// 1 (x1,y1)在 (x2,y2)的左边
// 2 (x1,y1)和(x2,y2)是同一个点
// 3 (x1,y1)在 (x2,y2)的右边
}

int vis[N];

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

int T;
ll p, a;
cin >> T;
while (T--) {
// init
top = 0;

cin >> n;

// y=1/2at^2+p -> 2y=a(t^2)+2p
for (int i = 1; i <= n; i++) {
cin >> p >> a;

L[i].k = a;
L[i].b = p * 2;

// init
vis[i] = 0; // 用于判断是否重线
}

sort(L + 1, L + 1 + n);

for (int i = 1, first, second, x; i <= n; i++) {
if (top && L[first = Stack[top]].k >= L[i].k) { // L[i]永远追不上第一
if (L[first] == L[i]) vis[first] = 1;//同一条直线 第一也不能要
continue;
}
if (top < 2) {
// 但是也存在后面的点和第一是同一个起点 加速度比第一大 即一开始大家都是第一 后一秒L[i]超过第一
if (top == 1 && L[first].b == L[i].b) {
Stack[top] = i;
} else
Stack[++top] = i;
} else {//top>=2
// 如果第一与第二的交点 在 第二与L[i]的右边 说明L[i]比第一先成领跑
while (top > 1 && check(L[first], L[second = Stack[top - 1]], L[i]) != 3) {
first = second;
top--;//踢掉第一
}
Stack[++top] = i;
}
}
int res = 0;
for (int i = 1; i <= top; i++) {
if (!vis[Stack[i]]) {
res++;
}
}
cout << res << endl;
}
return 0;
}


Math is Simple
Minimum Index

# Mow

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, k;
const double eps = 1e-8;
const double pi = acos(-1.0);

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

// ------------ 点、向量 ------------
struct Point {
double x, y;

Point() {}

Point(double _x, double _y) { x = _x, y = _y; }

void input() {
cin >> x >> y;
}//输入

Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }
Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }
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; }
//点积

double len() { return hypot(x, y); }
//返回长度

double distance(Point p) { return hypot(x - p.x, y - p.y); }
//两点之间的距离

Point trunc(double r) {
double l = len();
if (!sgn(l)) return *this;
r /= l;
return Point(x * r, y * r);
}//化为长度为r的向量

Point rotLeft() { return Point(-y, x); }
//逆时针旋转90°

Point rotRight() { return Point(y, -x); }
//顺时针旋转90°

Point normal(const bool rsh = false) {
return rsh ? rotLeft() : rotRight();
}// 法向量
};
typedef Point Vector;

// ------------ 直线 ------------
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;
}//用于极角排序

int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1; //点在直线的左侧
else if (c > 0) return 2;//点在直线的右侧
else return 3;//点在直线上
}//判断点与直线的关系

Point cross_point(Line v) {
double a1 = (v.e - v.s) ^(s - v.s);
double a2 = (v.e - v.s) ^(e - v.s);
return Point((s.x * a2 - e.x * a1) / (a2 - a1), (s.y * a2 - e.y * a1) / (a2 - a1));
}//求两直线的交点 前提：要保证直线不平行或重合

bool onLeft(Point p) {
return relation(p) == 1;
}
};

namespace Polygon { //多边形板子
// 求多边形的面积
// 顺时针还是逆时针都可 最终都会搞成逆时针
double polygon_area(vector<Point> &p) {
const int n = p.size();
double res = 0;
for (int i = 0; i < n; i++) {
res += p[i] ^ p[(i + 1) % n];
}
res /= 2;
if (sgn(res) < 0) {
reverse(p.begin(), p.end());
res *= -1;
}
return res;
}

// 半平面交求内核
vector<Point> HPI(vector<Line> L) {
const int n = L.size();
sort(L.begin(), L.end());
int first, last;//指向双端队列首尾元素
vector<Point> p(n);//两个相邻半平面的焦点
vector<Line> q(n);//模拟双端队列
vector<Point> res;//半平面交形成的凸包

q[first = last = 0] = L[0];
for (int i = 1; i < n; i++) {
//情况1 L[i]覆盖原队尾：删除尾元素 的半平面
while (first < last && !L[i].onLeft(p[last - 1])) last--;
//情况2 L[i]覆盖原队首：删除首元素的半平面
while (first < last && !L[i].onLeft(p[first])) first++;
q[++last] = L[i];//将当前的半平面加入双端队列的队尾
//极角相同的两个半平面保留左边的那个
if (sgn(q[last].v ^ q[last - 1].v) == 0) {//根据直线代表的向量判断是否平行
last--;
if (q[last].onLeft(L[i].s)) q[last] = L[i];
}
//计算队尾无用的半平面
if (first < last) p[last - 1] = q[last - 1].cross_point(q[last]);
}
//情况3 L[i]不能加入到队列： 删除队列首尾无用的半平面
while (first < last && !q[first].onLeft(p[last - 1])) last--;
if (last - first <= 1) return res;//空集
p[last] = q[last].cross_point(q[first]);//计算队列首尾的交点
return res = vector<Point>(p.begin() + first, p.begin() + last + 1);
}
}
using namespace Polygon;

ll r;//半径
ll A, B;

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

int T;
cin >> T;
for (int cs = 1; cs <= T; cs++) {
cin >> n >> r >> A >> B;
vector<Point> p(n);
for (int i = 0; i < n; i++) {
p[i].input();
}
//全手工费用
double s1 = polygon_area(p);
double res1 = s1 * A;
vector<Line> L;
for (int i = 0; i < n; i++) {
Vector nml = (p[(i + 1) % n] - p[i]).normal(1).trunc(r);//长度为r的法向量
L.push_back({p[i] + nml, p[(i + 1) % n] + nml});// 直线向内平移r个单位 <- 重点
}

vector<Point> core = HPI(L);
if (!core.empty()) {
m = core.size();
double c = 0;//周长
for (int i = 0; i < m; i++) {
c += core[i].distance(core[(i + 1) % m]);
}
// 新的面积 = 内核面积 + 内核周长*r + 一个圆
double s2 = polygon_area(core) + c * r + pi * r * r;
res1 = min(res1, (s1 - s2) * A + s2 * B);
}
// 输出20位数字 cout写法
cout << fixed << setprecision(20)  << res1 << endl;
}
return 0;
}

11-30

07-22 115