模拟。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int total = 0;
for (int i = 0; i < 4; ++i) {
int x;
scanf("%d", &x);
if (x) {
++total;
}
}
switch (total) {
case 0:
puts("Typically Otaku");
break;
case 1:
puts("Eye-opener");
break;
case 2:
puts("Young Traveller");
break;
case 3:
puts("Excellent Traveller");
break;
case 4:
puts("Contemporary Xu Xiake");
break;
}
}
return 0;
}
贪心,记 f ( x ) f(x) f(x) 表示造成 x x x 点伤害需要的时间,那么有两种方案:
输出方案贪心即可。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int hp_a, hp_b, attack_a, attack_b;
scanf("%d %d %d %d", &hp_a, &hp_b, &attack_a, &attack_b);
auto get_sum = [&](int x) {
return (long long)x * (x + 1) >> 1;
};
auto get_round = [&](int x) {
int result = 1;
while (get_sum(result) < x) {
++result;
}
return result;
};
int round_a = get_round(hp_a), round_b = get_round(hp_b), round_total = get_round(hp_a + hp_b);
long long answer = min((long long)attack_a * round_a + (long long)attack_b * round_total, (long long)attack_a * round_total + (long long)attack_b * round_b);
string result(round_total, 'B');
if ((long long)attack_a * round_a + (long long)attack_b * round_total == answer) {
string current(round_total, 'A');
for (int i = round_a; i < round_total; ++i) {
current[i] = 'B';
}
if (get_sum(round_a) - hp_a > get_sum(round_total) - hp_a - hp_b) {
current[get_sum(round_a) - hp_a - 1] = 'B';
}
result = min(result, current);
}
if ((long long)attack_a * round_total + (long long)attack_b * round_b == answer) {
string current(round_total, 'B');
for (int i = round_b; i < round_total; ++i) {
current[i] = 'A';
}
long long remain_b = get_sum(round_b) - hp_b, remain_a = remain_b - (get_sum(round_total) - hp_a - hp_b);
int last = -1;
for (int i = 0; i < round_a; ++i) {
if (remain_b >= i + 1) {
last = i;
current[i] = 'A';
remain_b -= i + 1;
remain_a -= i + 1;
}
}
if (remain_a > 0) {
current[last] = 'B';
current[last + remain_a] = 'A';
}
result = min(result, current);
}
cout << answer << " " << result << endl;
}
return 0;
}
考虑坐标时,显然两维独立。考虑一个点的位置,可以表示成 max ( l , min ( x , r ) ) + d \max(l, \min(x,r)) + d max(l,min(x,r))+d 的形式,可以快速维护。
再考虑第二问,不难发现棋盘可以用两条横线两条竖线划分成 9 9 9 部分,因为初始每行每列只有一个车,所以只有 4 4 4 个角的车会占领重复位置。在操作时移动分界线即可。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int n, m;
cin >> n >> m;
vector<int> x(n), y(n);
vector<int> px(n), py(n);
for (int i = 0; i < n; ++i) {
cin >> x[i] >> y[i];
--x[i];
--y[i];
px[x[i]] = i;
py[y[i]] = i;
}
int lx = 0, rx = n - 1, dx = 0;
int ly = 0, ry = n - 1, dy = 0;
int llx = -1, rrx = n;
int lly = -1, rry = n;
int ul = 0, ur = 0, dl = 0, dr = 0;
while (m--) {
string type;
cin >> type;
if (type == "U") {
int shift;
cin >> shift;
int low = max(lx + dx - shift, 0);
int high = max(rx + dx - shift, 0);
if (low == high) {
lx = rx = 0;
} else {
lx = rx - high + low;
}
dx = high - rx;
} else if (type == "D") {
int shift;
cin >> shift;
int low = min(lx + dx + shift, n - 1);
int high = min(rx + dx + shift, n - 1);
if (low == high) {
lx = rx = 0;
} else {
rx = lx + high - low;
}
dx = low - lx;
} else if (type == "L") {
int shift;
cin >> shift;
int low = max(ly + dy - shift, 0);
int high = max(ry + dy - shift, 0);
if (low == high) {
ly = ry = 0;
} else {
ly = ry - high + low;
}
dy = high - ry;
} else if (type == "R") {
int shift;
cin >> shift;
int low = min(ly + dy + shift, n - 1);
int high = min(ry + dy + shift, n - 1);
if (low == high) {
ly = ry = 0;
} else {
ry = ly + high - low;
}
dy = low - ly;
} else if (type == "?") {
int id;
cin >> id;
--id;
printf("%d %d\n", max(lx, min(rx, x[id])) + dx + 1, max(ly, min(ry, y[id])) + dy + 1);
} else if (type == "!") {
auto get = [&](int x) {
return (long long)x * (x - 1) >> 1;
};
long long answer = 0;
if (lx == rx && ly == ry) {
printf("%lld\n", get(n));
} else if (lx == rx) {
printf("%lld\n", get(ly + 1) + get(n - ry));
} else if (ly == ry) {
printf("%lld\n", get(lx + 1) + get(n - rx));
} else {
while (llx < lx) {
++llx;
int id = px[llx];
if (y[id] <= lly) {
++ul;
}
if (y[id] >= rry) {
++ur;
}
}
while (rrx > rx) {
--rrx;
int id = px[rrx];
if (y[id] <= lly) {
++dl;
}
if (y[id] >= rry) {
++dr;
}
}
while (lly < ly) {
++lly;
int id = py[lly];
if (x[id] <= llx) {
++ul;
}
if (x[id] >= rrx) {
++dl;
}
}
while (rry > ry) {
--rry;
int id = py[rry];
if (x[id] <= llx) {
++ur;
}
if (x[id] >= rrx) {
++dr;
}
}
printf("%lld\n", get(ul) + get(ur) + get(dl) + get(dr));
}
}
}
}
return 0;
}
分是否取到最大值两种情况讨论一下。
#include
using namespace std;
const double pi = acos(-1);
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int a, b, r, d;
scanf("%d %d %d %d", &a, &b, &r, &d);
double angle = d * pi / 180;
if (angle >= atan((double)b / (a + r))) {
printf("%.9lf\n", sqrt(b * b + (a + r) * (a + r)) - r);
} else {
printf("%.9lf\n", (r + a) * cos(angle) + b * sin(angle) - r);
}
}
return 0;
}
考虑最后选择了 ∏ i = 1 k p i \prod_{i=1}^k p_i ∏i=1kpi ,那么其贡献是 ∏ i = 1 k p i + 1 p i \prod_{i=1}^k \frac{p_i+1}{p_i} ∏i=1kpipi+1 ,选前若干小的质数即可。
def gcd(x, y):
if y:
return gcd(y, x % y)
return x
tt = int(raw_input())
p = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231]
while tt:
n = int(raw_input())
num = 1
den = 1
for i in range(0, 200):
if den * p[i] > n:
break
num *= p[i] + 1
den *= p[i]
g = gcd(den, num)
print str(den / g) + '/' + str(num / g)
tt = tt - 1
模拟。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
string foo;
int tt;
{
getline(cin, foo);
stringstream ss;
ss << foo;
ss >> tt;
}
while (tt--) {
int n, m;
{
getline(cin, foo);
stringstream ss;
ss << foo;
ss >> n >> m;
}
vector<string> board(n * 4 + 3);
for (int i = 0; i < n * 4 + 3; ++i) {
getline(cin, board[i]);
board[i].resize(m * 6 + 3);
}
vector<vector<int>> adj(n * m);
int source = -1, sink = -1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int shift = j & 1 ? 2 : 0;
if (board[i * 4 + 2 + shift][j * 6 + 4] == 'S') {
source = i * m + j;
}
if (board[i * 4 + 2 + shift][j * 6 + 4] == 'T') {
sink = i * m + j;
}
if (board[i * 4 + shift][j * 6 + 4] == ' ') {
int ni = i - 1, nj = j;
adj[i * m + j].push_back(ni * m + nj);
adj[ni * m + nj].push_back(i * m + j);
}
if (board[i * 4 + 1 + shift][j * 6 + 7] == ' ') {
int ni = i - !(j & 1), nj = j + 1;
adj[i * m + j].push_back(ni * m + nj);
adj[ni * m + nj].push_back(i * m + j);
}
if (board[i * 4 + 3 + shift][j * 6 + 7] == ' ') {
int ni = i + (j & 1), nj = j + 1;
adj[i * m + j].push_back(ni * m + nj);
adj[ni * m + nj].push_back(i * m + j);
}
}
}
vector<int> dist(n * m, -1);
queue<int> q;
dist[source] = 1;
q.push(source);
while (!q.empty()) {
int x = q.front();
q.pop();
for (auto y : adj[x]) {
if (!~dist[y]) {
dist[y] = dist[x] + 1;
q.push(y);
}
}
}
printf("%d\n", dist[sink]);
}
return 0;
}
记 f ( n ) f(n) f(n) 表示 n n n 个点的森林个数, g ( n ) g(n) g(n) 表示 n n n 个点的森林可达点对的个数, h ( n ) h(n) h(n) 表示 n n n 个点森林可达点对距离平方之和, t ( n ) t(n) t(n) 表示 n n n 个点的树个数, F ( x ) , G ( x ) , H ( x ) , T ( x ) F(x), G(x), H(x), T(x) F(x),G(x),H(x),T(x) 表示其对应的EGF。那么:
#include
using namespace std;
const int md = 998244353;
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline void sub(int &x, int y) {
x -= y;
if (x < 0) {
x += md;
}
}
inline int mul(int x, int y) {
return (long long)x * y % md;
}
inline int power(int x, int y) {
int result = 1;
for (; y; y >>= 1, x = mul(x, x)) {
if (y & 1) {
result = mul(result, x);
}
}
return result;
}
namespace ntt {
int base = 1, root = -1, max_base = -1;
vector<int> roots = {0, 1}, rev = {0, 1}, inv = {1, 1};
void init() {
int temp = md - 1;
max_base = 0;
while (!(temp & 1)) {
temp >>= 1;
++max_base;
}
root = 2;
while (true) {
if (power(root, 1 << max_base) == 1 && power(root, 1 << max_base - 1) != 1) {
break;
}
++root;
}
}
void ensure_base(int nbase) {
if (max_base == -1) {
init();
}
if (nbase <= base) {
return;
}
assert(nbase <= max_base);
rev.resize(1 << nbase);
for (int i = 0; i < (1 << nbase); ++i) {
rev[i] = rev[i >> 1] >> 1 | ((i & 1) << nbase - 1);
}
roots.resize(1 << nbase);
while (base < nbase) {
int z = power(root, 1 << max_base - 1 - base);
for (int i = 1 << base - 1; i < 1 << base; ++i) {
roots[i << 1] = roots[i];
roots[i << 1 | 1] = mul(roots[i], z);
}
++base;
}
}
void dft(vector<int> &a) {
int n = a.size(), zeros = __builtin_ctz(n);
ensure_base(zeros);
int shift = base - zeros;
for (int i = 0; i < n; ++i) {
if (i < rev[i] >> shift) {
swap(a[i], a[rev[i] >> shift]);
}
}
for (int i = 1; i < n; i <<= 1) {
for (int j = 0; j < n; j += i << 1) {
for (int k = 0; k < i; ++k) {
int x = a[j + k], y = mul(a[j + k + i], roots[i + k]);
a[j + k] = (x + y) % md;
a[j + k + i] = (x + md - y) % md;
}
}
}
}
void psub(vector<int> &a, vector<int> b) {
if (a.size() < b.size()) {
a.resize(b.size());
}
for (int i = 0; i < b.size(); ++i) {
sub(a[i], b[i]);
}
}
vector<int> pmul(vector<int> a, vector<int> b, bool equal = false) {
int need = a.size() + b.size() - 1, nbase = 0;
while (1 << nbase < need) {
++nbase;
}
ensure_base(nbase);
int size = 1 << nbase;
a.resize(size);
b.resize(size);
dft(a);
if (equal) {
b = a;
} else {
dft(b);
}
int inv = power(size, md - 2);
for (int i = 0; i < size; ++i) {
a[i] = mul(mul(a[i], b[i]), inv);
}
reverse(a.begin() + 1, a.end());
dft(a);
a.resize(need);
return a;
}
vector<int> psqr(vector<int> a) {
return pmul(a, a, true);
}
vector<int> pinv(vector<int> a) {
int n = a.size(), m = n + 1 >> 1;
if (n == 1) {
return vector<int> (1, power(a[0], md - 2));
} else {
vector<int> b = pinv(vector<int> (a.begin(), a.begin() + m));
int need = n << 1, nbase = 0;
while (1 << nbase < need) {
++nbase;
}
ensure_base(nbase);
int size = 1 << nbase;
a.resize(size);
b.resize(size);
dft(a);
dft(b);
int inv = power(size, md - 2);
for (int i = 0; i < size; ++i) {
a[i] = mul(mul(md + 2 - mul(a[i], b[i]), b[i]), inv);
}
reverse(a.begin() + 1, a.end());
dft(a);
a.resize(n);
return a;
}
}
vector<int> pder(vector<int> a) {
vector<int> b(a.size() - 1);
for (int i = 0; i < b.size(); ++i) {
b[i] = mul(a[i + 1], i + 1);
}
return b;
}
vector<int> pint(vector<int> a) {
vector<int> b(a.size() + 1);
while (inv.size() < b.size()) {
int n = inv.size();
inv.push_back(mul(md - md / n, inv[md % n]));
}
for (int i = 1; i < b.size(); ++i) {
b[i] = mul(a[i - 1], inv[i]);
}
return b;
}
vector<int> pln(vector<int> a) {
vector<int> b = pint(pmul(pder(a), pinv(a)));
b.resize(a.size());
return b;
}
vector<int> pexp(vector<int> a) {
int n = a.size();
if (n == 1) {
return vector<int> (1, 1);
} else {
int m = n + 1 >> 1;
vector<int> b = pexp(vector<int> (a.begin(), a.begin() + m));
b.resize(n);
psub(a, pln(b));
add(a[0], 1);
b = pmul(b, a);
b.resize(n);
return b;
}
}
}
using ntt::pmul;
using ntt::psqr;
using ntt::pexp;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
vector<int> qn(tt), qm(tt);
for (int i = 0; i < tt; ++i) {
scanf("%d %d", &qn[i], &qm[i]);
}
int n = *max_element(qn.begin(), qn.end()) + 1;
vector<int> fact(n), inv_fact(n);
fact[0] = fact[1] = inv_fact[0] = inv_fact[1] = 1;
for (int i = 2; i < n; ++i) {
fact[i] = mul(fact[i - 1], i);
inv_fact[i] = mul(md - md / i, inv_fact[md % i]);
}
for (int i = 2; i < n; ++i) {
inv_fact[i] = mul(inv_fact[i - 1], inv_fact[i]);
}
vector<int> f(n);
f[1] = 1;
for (int i = 2; i < n; ++i) {
f[i] = mul(power(i, i - 2), inv_fact[i]);
}
f = pexp(f);
vector<int> g(n);
for (int i = 2; i < n; ++i) {
g[i] = mul(mul(md + 1 >> 1, mul(i - 1, power(i, i - 1))), inv_fact[i]);
}
g = pmul(g, f);
g.resize(n);
vector<int> base(n);
for (int i = 1; i < n; ++i) {
base[i] = mul(power(i, i), inv_fact[i]);
}
vector<int> sum = psqr(base);
sum.resize(n);
vector<int> sqr = pmul(sum, base);
sqr.resize(n);
vector<int> h(n);
for (int i = 0; i < n; ++i) {
h[i] = (mul(sqr[i], 2) + sum[i]) % md;
}
h = pmul(h, f);
h.resize(n);
for (int i = 0; i < n; ++i) {
f[i] = mul(f[i], fact[i]);
g[i] = mul(g[i], fact[i]);
h[i] = mul(h[i], fact[i]);
}
for (int qq = 0; qq < tt; ++qq) {
int n = qn[qq], m = qm[qq];
int inside = mul(md + 1 >> 1, h[n]);
int outside = mul(f[n], mul(md + 1 >> 1, mul(n, n - 1)));
sub(outside, g[n]);
outside = mul(outside, mul(m, m));
add(inside, outside);
inside = mul(inside, power(f[n], md - 2));
printf("%d\n", inside);
}
return 0;
}
考虑后缀数组求本质不同子串个数的方法,相当于求某个位置开头,某段区间结尾的区间最大值。单调栈加线段树维护即可。
#include
using namespace std;
template<typename T> vector<int> suffix_array(const T &s, int n, int alpha) {
vector<int> a(n);
if (~alpha) {
vector<int> bucket(alpha);
for (int i = 0; i < n; ++i) {
++bucket[s[i]];
}
int sum = 0;
for (int i = 0; i < alpha; ++i) {
int add = bucket[i];
bucket[i] = sum;
sum += add;
}
for (int i = 0; i < n; ++i) {
a[bucket[s[i]]++] = i;
}
} else {
for (int i = 0; i < n; ++i) {
a[i] = i;
}
sort(a.begin(), a.end(), [&](const int &x, const int &y) {
return s[x] < s[y];
});
}
vector<int> sorted_by_second(n);
vector<int> ptr_group(n);
vector<int> new_group(n);
vector<int> group(n);
group[a[0]] = 0;
for (int i = 1; i < n; ++i) {
group[a[i]] = group[a[i - 1]] + (s[a[i]] != s[a[i - 1]]);
}
int step = 1;
while (group[a[n - 1]] < n - 1) {
int ptr = 0;
for (int i = n - step; i < n; ++i) {
sorted_by_second[ptr++] = i;
}
for (int i = 0; i < n; ++i) {
if (a[i] >= step) {
sorted_by_second[ptr++] = a[i] - step;
}
}
for (int i = n - 1; ~i; --i) {
ptr_group[group[a[i]]] = i;
}
for (int i = 0; i < n; ++i) {
int x = sorted_by_second[i];
a[ptr_group[group[x]]++] = x;
}
new_group[a[0]] = 0;
for (int i = 1; i < n; ++i) {
if (group[a[i]] != group[a[i - 1]]) {
new_group[a[i]] = new_group[a[i - 1]] + 1;
} else {
int prev = a[i - 1] + step >= n ? -1 : group[a[i - 1] + step];
int now = a[i] + step >= n ? -1 : group[a[i] + step];
new_group[a[i]] = new_group[a[i - 1]] + (prev != now);
}
}
group = new_group;
step <<= 1;
}
return a;
}
template<typename T> vector<int> build_lcp(const T &s, int n, const vector<int> &sa) {
vector<int> pos(n);
for (int i = 0; i < n; ++i) {
pos[sa[i]] = i;
}
vector<int> lcp(n - 1);
for (int i = 0, k = 0; i < n; ++i) {
k = max(k - 1, 0);
if (pos[i] == n - 1) {
k = 0;
} else {
int j = sa[pos[i] + 1];
while (i + k < n && j + k < n && s[i + k] == s[j + k]) {
++k;
}
lcp[pos[i]] = k;
}
}
return lcp;
}
class segtree_t {
public:
struct node_t {
long long sum = 0, tag = 0;
void apply(int l, int r, long long v) {
sum += v * (r - l + 1);
tag += v;
}
};
vector<node_t> tree;
int n;
node_t unite(const node_t &l, const node_t &r) {
node_t result;
result.sum = l.sum + r.sum;
return result;
}
segtree_t(int n):n(n) {
tree.resize((n << 1) - 1);
}
inline void pull(int x, int z) {
tree[x] = unite(tree[x + 1], tree[z]);
}
inline void push(int x, int l, int r) {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
if (tree[x].tag) {
tree[x + 1].apply(l, y, tree[x].tag);
tree[z].apply(y + 1, r, tree[x].tag);
tree[x].tag = 0;
}
}
void build(int x, int l, int r) {
if (l != r) {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
build(x + 1, l, y);
build(z, y + 1, r);
pull(x, z);
}
}
template<typename T> void build(int x, int l, int r, const vector<T> &v) {
if (l == r) {
tree[x].apply(l, r, v[l]);
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
build(x + 1, l, y, v);
build(z, y + 1, r, v);
pull(x, z);
}
}
template<typename T> void build(const vector<T> &v) {
build(0, 0, n - 1, v);
}
template<typename... T> void modify(int x, int l, int r, int ql, int qr, const T&... v) {
if (l == ql && r == qr) {
tree[x].apply(l, r, v...);
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
push(x, l, r);
if (qr <= y) {
modify(x + 1, l, y, ql, qr, v...);
} else if (ql > y) {
modify(z, y + 1, r, ql, qr, v...);
} else {
modify(x + 1, l, y, ql, y, v...);
modify(z, y + 1, r, y + 1, qr, v...);
}
pull(x, z);
}
}
template<typename... T> void modify(int l, int r, const T&... v) {
modify(0, 0, n - 1, l, r, v...);
}
node_t query(int x, int l, int r, int ql, int qr) {
if (l == ql && r == qr) {
return tree[x];
} else {
int y = l + r >> 1, z = x + (y - l + 1 << 1);
push(x, l, r);
if (qr <= y) {
return query(x + 1, l, y, ql, qr);
} else if (ql > y) {
return query(z, y + 1, r, ql, qr);
} else {
return unite(query(x + 1, l, y, ql, y), query(z, y + 1, r, y + 1, qr));
}
}
}
node_t query(int l, int r) {
return query(0, 0, n - 1, l, r);
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int n;
scanf("%d", &n);
vector<int> a(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
vector<int> sa = suffix_array(a, n, -1);
vector<int> pos_in_sa(n);
for (int i = 0; i < n; ++i) {
pos_in_sa[sa[i]] = i;
}
vector<int> lcp = build_lcp(a, n, sa);
segtree_t segtree(n);
segtree.build(a);
vector<int> st;
st.push_back(n);
a.push_back(1 << 30);
long long answer = 0;
for (int i = n - 1; ~i; --i) {
while (a[i] >= a[st.back()]) {
segtree.modify(st[st.size() - 1], st[st.size() - 2] - 1, a[i] - a[st.back()]);
st.pop_back();
}
st.push_back(i);
int l = i;
if (pos_in_sa[i] != n - 1) {
l += lcp[pos_in_sa[i]];
}
if (l < n) {
answer += segtree.query(l, n - 1).sum;
}
}
printf("%lld\n", answer);
}
return 0;
}
贪心。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int n;
scanf("%d", &n);
vector<int> x(n);
for (int i = 0; i < n - 1; ++i) {
scanf("%d", &x[i + 1]);
x[i + 1] += x[i];
}
long long answer = 0;
long long lsum = 0, rsum = 0;
int lcnt = 0, rcnt = 0;
for (int i = 0; i < n; ++i) {
if (i & 1) {
if (lcnt < rcnt) {
answer += rsum - (long long)rcnt * x[lcnt] + (long long)lcnt * x[lcnt] - lsum;
lsum += x[lcnt];
++lcnt;
} else {
answer += rsum - (long long)rcnt * x[n - rcnt - 1] + (long long)lcnt * x[n - rcnt - 1] - lsum;
rsum += x[n - rcnt - 1];
++rcnt;
}
} else {
long long lvalue = rsum - (long long)rcnt * x[lcnt] + (long long)lcnt * x[lcnt] - lsum;
long long rvalue = rsum - (long long)rcnt * x[n - rcnt - 1] + (long long)lcnt * x[n - rcnt - 1] - lsum;
if (lvalue > rvalue) {
answer += lvalue;
lsum += x[lcnt];
++lcnt;
} else {
answer += rvalue;
rsum += x[n - rcnt - 1];
++rcnt;
}
}
printf("%lld%c", answer, i == n - 1 ? '\n' : ' ');
}
}
return 0;
}
对于每个格子,如果它被 0 0 0 块或者大于 2 2 2 块地毯覆盖,那么可以无视它。否则如果能求出覆盖它的地毯 x x x 或者 ( x , y ) (x,y) (x,y) ,那么就可以算出答案了。 x x x 可以直接用前缀和求,考虑 ( x , y ) (x,y) (x,y) ,可以记录平方和求出 x 2 + y 2 x^2+y^2 x2+y2 ,然后解出 x , y x,y x,y 即可。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int n, m;
scanf("%d %d", &n, &m);
vector<int> xl(n), xr(n), yl(n), yr(n);
vector<vector<int>> cnt(m + 1, vector<int> (m + 1));
vector<vector<int>> sum(m + 1, vector<int> (m + 1));
vector<vector<long long>> sqr(m + 1, vector<long long> (m + 1));
for (int i = 0; i < n; ++i) {
scanf("%d %d %d %d", &xl[i], &xr[i], &yl[i], &yr[i]);
--xl[i];
--yl[i];
++cnt[xl[i]][yl[i]];
++cnt[xr[i]][yr[i]];
--cnt[xr[i]][yl[i]];
--cnt[xl[i]][yr[i]];
sum[xl[i]][yl[i]] += i;
sum[xr[i]][yr[i]] += i;
sum[xr[i]][yl[i]] -= i;
sum[xl[i]][yr[i]] -= i;
sqr[xl[i]][yl[i]] += (long long)i * i;
sqr[xr[i]][yr[i]] += (long long)i * i;
sqr[xr[i]][yl[i]] -= (long long)i * i;
sqr[xl[i]][yr[i]] -= (long long)i * i;
--xr[i];
--yr[i];
}
vector<pair<int, int>> all;
vector<int> single(n);
int free = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
if (i) {
cnt[i][j] += cnt[i - 1][j];
sum[i][j] += sum[i - 1][j];
sqr[i][j] += sqr[i - 1][j];
}
if (j) {
cnt[i][j] += cnt[i][j - 1];
sum[i][j] += sum[i][j - 1];
sqr[i][j] += sqr[i][j - 1];
}
if (i && j) {
cnt[i][j] -= cnt[i - 1][j - 1];
sum[i][j] -= sum[i - 1][j - 1];
sqr[i][j] -= sqr[i - 1][j - 1];
}
if (!cnt[i][j]) {
++free;
} else if (cnt[i][j] == 1) {
++single[sum[i][j]];
} else if (cnt[i][j] == 2) {
int diff = sqrt(2 * sqr[i][j] - (long long)sum[i][j] * sum[i][j]);
int x = sum[i][j] + diff >> 1;
int y = sum[i][j] - diff >> 1;
all.emplace_back(x, y);
}
}
}
int first = 0, second = 0;
for (int i = 0; i < n; ++i) {
second = max(second, single[i]);
if (second > first) {
swap(first, second);
}
}
int answer = first + second;
sort(all.begin(), all.end());
for (int i = 0, j = 0; i < all.size(); i = j) {
while (j < all.size() && all[j] == all[i]) {
++j;
}
answer = max(answer, single[all[i].first] + single[all[i].second] + j - i);
}
printf("%d\n", m * m - free - answer);
}
return 0;
}
哈希,二分预处理每个位置开头第一次失配的位置,然后倍增失配的过程即可。
#include
using namespace std;
const int base = 2333;
const int md0 = 1e9 + 7;
const int md1 = 1e9 + 9;
struct hash_t {
int hash0, hash1;
hash_t(int hash0 = 0, int hash1 = 0): hash0(hash0), hash1(hash1) {
}
hash_t operator + (const int &x) const {
return hash_t((hash0 + x) % md0, (hash1 + x) % md1);
};
hash_t operator * (const int &x) const {
return hash_t((long long)hash0 * x % md0, (long long)hash1 * x % md1);
}
hash_t operator + (const hash_t &x) const {
return hash_t((hash0 + x.hash0) % md0, (hash1 + x.hash1) % md1);
};
hash_t operator - (const hash_t &x) const {
return hash_t((hash0 + md0 - x.hash0) % md0, (hash1 + md1 - x.hash1) % md1);
};
hash_t operator * (const hash_t &x) const {
return hash_t((long long)hash0 * x.hash0 % md0, (long long)hash1 * x.hash1 % md1);
}
inline long long get() {
return (long long)hash0 * md1 + hash1;
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
int tt;
cin >> tt;
while (tt--) {
int n, m, q;
cin >> n >> m >> q;
vector<vector<pair<int, char>>> adj(n + 1);
for (int i = 1; i <= n; ++i) {
int x;
string s;
cin >> x >> s;
adj[x].emplace_back(i, s[0]);
}
string s;
cin >> s;
vector<hash_t> hash(m + 1), power(m + 1);
power[0] = hash_t(1, 1);
for (int i = 0; i < m; ++i) {
power[i + 1] = power[i] * base;
hash[i + 1] = hash[i] * base + s[i];
}
unordered_map<long long, int> pos;
function<void(int, hash_t)> dfs = [&](int x, hash_t h) {
pos[h.get()] = x;
for (auto p : adj[x]) {
dfs(p.first, h * base + p.second);
}
};
dfs(0, hash_t(0, 0));
int log_m = 0;
while (1 << log_m <= m) {
++log_m;
}
auto get = [&](int l, int r) {
return (hash[r] - hash[l] * power[r - l]).get();
};
vector<vector<int>> go(log_m, vector<int> (m + 1));
for (int i = 0; i <= m; ++i) {
int l = 0, r = m - i;
while (l < r) {
int mid = l + r + 1 >> 1;
long long h = get(i, i + mid);
if (pos.find(h) != pos.end()) {
l = mid;
} else {
r = mid - 1;
}
}
go[0][i] = i + l + 1;
}
for (int i = 1; i < log_m; ++i) {
for (int j = 0; j <= m; ++j) {
if (go[i - 1][j] > m) {
go[i][j] = go[i - 1][j];
} else {
go[i][j] = go[i - 1][go[i - 1][j]];
}
}
}
while (q--) {
int l, r;
cin >> l >> r;
--l;
int answer = 0;
for (int i = log_m - 1; ~i; --i) {
if (go[i][l] <= r) {
answer += 1 << i;
l = go[i][l];
}
}
printf("%d %d\n", answer, pos[get(l, r)]);
}
}
return 0;
}
分类讨论一下,大概要数几个东西:
正戊烷
异戊烷
新戊烷
三元环接上一条边
四元环个数
用简单容斥可以算出答案。这里难点是数四元环,考虑将边定向,从点度小的指向点度大的,那么显然一个点的出度不超过 m \sqrt m m 。假设环是 a − b − c − d a-b-c-d a−b−c−d ,且度数最大的点为 a a a ,那么枚举 c c c ,在 b b b 处将 a a a 处的标记加上 1 1 1 ,在 d d d 处加上 a a a 的标记即可。
#include
using namespace std;
const int md = 1e9 + 7;
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline void sub(int &x, int y) {
x -= y;
if (x < 0) {
x += md;
}
}
inline int mul(int x, int y) {
return (long long)x * y % md;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
while (tt--) {
int n, m;
scanf("%d %d", &n, &m);
vector<vector<int>> adj(n), graph(n);
for (int i = 0; i < m; ++i) {
int x, y;
scanf("%d %d", &x, &y);
--x;
--y;
adj[x].push_back(y);
adj[y].push_back(x);
}
vector<int> order(n);
for (int i = 0; i < n; ++i) {
order[i] = i;
}
sort(order.begin(), order.end(), [&](int x, int y) {
return adj[x].size() < adj[y].size();
});
vector<int> pos(n);
for (int i = 0; i < n; ++i) {
pos[order[i]] = i;
}
for (int x = 0; x < n; ++x) {
for (auto y : adj[x]) {
if (pos[x] < pos[y]) {
graph[x].push_back(y);
}
}
}
auto solve_a = [&]() {
int answer = 0;
for (int x = 0; x < n; ++x) {
int sum = 0;
for (auto y : adj[x]) {
int coef = adj[y].size() - 1;
add(answer, mul(sum, coef));
add(sum, coef);
}
}
return answer;
};
auto solve_b = [&]() {
int answer = 0;
for (int x = 0; x < n; ++x) {
int ways = mul(md + 1 >> 1, mul(adj[x].size() - 1, adj[x].size() - 2));
if (ways) {
for (auto y : adj[x]) {
add(answer, mul(adj[y].size() - 1, ways));
}
}
}
return answer;
};
auto solve_c = [&]() {
int answer = 0;
for (int x = 0; x < n; ++x) {
int coef = 41666667;
for (int i = 0; i < 4; ++i) {
coef = mul(coef, adj[x].size() - i);
}
add(answer, coef);
}
return answer;
};
auto solve_d = [&]() {
vector<bool> connect(n);
int answer = 0;
for (int x = 0; x < n; ++x) {
for (auto y : graph[x]) {
connect[y] = true;
}
for (auto y : graph[x]) {
for (auto z : graph[y]) {
if (connect[z]) {
add(answer, adj[x].size() + adj[y].size() + adj[z].size() - 5);
}
}
}
for (auto y : graph[x]) {
connect[y] = false;
}
}
return answer;
};
auto solve_e = [&]() {
vector<int> value(n);
int answer = 0;
for (int x = 0; x < n; ++x) {
for (auto y : adj[x]) {
for (auto z : graph[y]) {
if (pos[z] > pos[x]) {
add(answer, value[z]);
++value[z];
}
}
}
for (auto y : adj[x]) {
for (auto z : graph[y]) {
if (pos[z] > pos[x]) {
value[z] = 0;
}
}
}
}
return answer;
};
int answer = 0;
add(answer, solve_a());
add(answer, solve_b());
add(answer, solve_c());
sub(answer, mul(3, solve_d()));
sub(answer, mul(3, solve_e()));
printf("%d\n", answer);
}
return 0;
}