贪心 + 笛卡尔树,主席树 + 标记永久化,推式子 + 矩阵乘法

啥都不会,只会骗分 QwQ,没有想到的是 T2 O(n2)O(n^2) 预处理,O(mlogn)O(m \log n) 查询能得 90pts,T3 __int128 竟然存的下 f30f_{30}!充分告诉我们要有信仰 qaq

# A. 「2017 山东二轮集训 Day1」第二题

看起来是这套题里面最简单的了。

大力贪心。

每次找到最低点,然后分治处理两边。

答案分别加上两边的大小除以 kk,然后多余的部分送给最低点统计。

可以通过建笛卡尔树找最低点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <bits/stdc++.h>
#define int long long

using namespace std;

namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}

template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;

const int N = 1e5 + 10;
int n, k;
int h[N];

#define ls t[x].l
#define rs t[x].r
struct Tree{
int l, r;
}t[N];
int stk[N], top, res;
int rt, ans;
int sum[N], siz[N];

inline void dfs(int x, int fa){
siz[x] = 1;
if(ls) dfs(ls, x), sum[x] += sum[ls], siz[x] += siz[ls];
if(rs) dfs(rs, x), sum[x] += sum[rs], siz[x] += siz[rs];
sum[x] += siz[x] * (h[x] - h[fa]);
if(sum[x] > 0){
int tot = ceil(1.0 * sum[x] / k);
ans += tot, sum[x] -= tot * k;
}
}

signed main(){
n = read(), k = read();
for(int i = 1; i <= n; ++i) h[i] = read();
for(int i = 1; i <= n; ++i, res = 0){
while(top && h[stk[top]] > h[i]) res = stk[top--];
t[i].l = res, t[stk[top]].r = i, stk[++top] = i;
}
rt = stk[1];
dfs(rt, 0);
write(ans), puts("");
return 0;
}
// X.K.

# B. 「2017 山东二轮集训 Day1」第一题

毒瘤数据结构。

大致思路是找出每个点向右能到达的最远的点,然后把这个贡献加到主席树里,查询的时候直接在主席树上查询 lrl \sim r 的区间和即可。

那么如何预处理呢?

s[0/1][i][j]s[0/1][i][j] 为前 ii 个数的异或和,最高位 jj101 \rightarrow 0010 \rightarrow 1 的个数,sumisum_i 为前缀异或和。

对于区间 lrl \sim r,如果 suml1sum_{l - 1} 的最高位 jj 为 1,那么 lrl \sim r 中第 jj 位就不能出现 101 \rightarrow 0,反之不能出现 010 \rightarrow 1

所以可以使用二分查找。

然后在主席树进行区间加,这需要使用标记永久化。

所谓标记永久化其实就是修改时不写 pushdown\text{pushdown},只在查询的时候加上标记的贡献即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <bits/stdc++.h>
#define ll long long

using namespace std;

namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}

template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;

const int N = 2e5 + 10;
int n, m, lst;
int a[N], pos[N], sum[N];
int s[2][N][66];

inline int highbit(int x){
for(int i = 30; i >= 0; --i) if((x >> i) & 1) return i;
return -1;
}
inline int bit(int x, int y) {return (x >> y) & 1;}

inline bool check(int l, int r){
for(int i = 30; i >= 0; --i){
int x = !bit(sum[l - 1], i);
if(s[x][r][i] - s[x][l - 1][i] > 0) return 0;
}
return 1;
}

inline int find(int x){
int l = x, r = n, res = x;
while(l <= r){
int mid = (l + r) >> 1;
if(check(x, mid)) res = mid, l = mid + 1;
else r = mid - 1;
}
return res;
}

#define ls(x) t[x].l
#define rs(x) t[x].r
int rt[N], cnt;
struct Tree{
int val, tag, l, r;
}t[N << 5];

inline int build(int l, int r){
int p = ++cnt;
if(l == r) return p;
int mid = (l + r) >> 1;
ls(p) = build(l, mid), rs(p) = build(mid + 1, r);
return p;
}

inline int update(int pre, int L, int R, int k, int l, int r){
int p = ++cnt;
t[p] = t[pre];
if(L == l && R == r) return t[p].tag += k, p;
t[p].val += k * (R - L + 1);
int mid = (l + r) >> 1;
if(L <= mid) ls(p) = update(ls(pre), L, min(R, mid), k, l, mid);
if(R > mid) rs(p) = update(rs(pre), max(L, mid + 1), R, k, mid + 1, r);
return p;
}

inline int query(int x, int y, int L, int R, int l, int r){
int res = (t[y].tag - t[x].tag) * (R - L + 1);
if(L == l && R == r) return res + t[y].val - t[x].val;
int mid = (l + r) >> 1;
if(L <= mid) res += query(ls(x), ls(y), L, min(R, mid), l, mid);
if(R > mid) res += query(rs(x), rs(y), max(L, mid + 1), R, mid + 1, r);
return res;
}

signed main(){
n = read();
for(int i = 1; i <= n; ++i){
sum[i] = sum[i - 1] ^ (a[i] = read());
for(int j = 0; j <= 30; ++j) s[0][i][j] = s[0][i - 1][j], s[1][i][j] = s[1][i - 1][j];
int j = highbit(a[i]);
if(~j) s[bit(sum[i - 1], j)][i][j]++;
}
for(int i = 1; i <= n; ++i) pos[i] = find(i);
rt[0] = build(1, n);
for(int i = 1; i <= n; ++i) rt[i] = update(rt[i - 1], i, pos[i], 1, 1, n);
m = read();
while(m--){
int l = (read() + lst) % n + 1, r = (read() + lst) % n + 1;
if(l > r) swap(l, r);
write(lst = query(rt[l - 1], rt[r], l, r, 1, n)), puts("");
}
return 0;
}
// X.K.

# C. GCD

这道题就相当之困难了。

题目让我们求 gcd(afn+bfn+1,cfn+dfn+1)\gcd(af_n + bf_{n + 1}, cf_n + df_{n + 1})

首先通过更相减损术可以去掉 dfn+1df_{n + 1} 这一项。

式子就变成了 gcd(afn+bfn+1,cfn)\gcd(a'f_n + b'f_{n + 1}, c'f_n)

我们把 cc'fnf_n 分开计算:

  • gcd(afn+bfn+1,fn)=gcd(bfn+1,fn)\gcd(af_n + bf_{n + 1}, f_n) = \gcd(bf_{n + 1}, f_n)

    通过打表发现,gcd(fn,fn+1)=3n2\gcd(f_n, f_{n + 1}) = 3^{\frac n2},所以就是 gcd(b,fn)×3n2\gcd(b, f_n) \times 3^{\frac n2}

  • gcd(afn+bfn+1,c)\gcd(af_n + bf_{n + 1}, c),设 g=gcd(afn+bfn+1,fn)g = \gcd(af_n + bf_{n + 1}, f_n),然后先除掉这一部分,即求 gcd(afn+bfn+1g,c)\gcd(\frac {af_n + bf_{n + 1}}g, c),然后让左边模 gcgc 计算即可。

所以答案就是:

gcd(afn+bfn+1modgcg,c)×g×3n2modp\gcd(\frac {af_n + bf_{n + 1} \bmod gc}g, c) \times g \times 3^{\frac n2} \bmod p

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <bits/stdc++.h>
#define int long long

using namespace std;

namespace IO{
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}

template <typename T> inline void write(T x){
if(x < 0) x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;

const int N = 1e6;
int T, n, p, a, b, c, d;
int mod = 998244353;

struct Matrix{
int num[2][2];

Matrix (){memset(num, 0, sizeof(num));}
inline void init (){num[0][0] = num[0][1] = 1;}

Matrix operator / (int b) const{
Matrix r;
for(int i = 0; i < 2; ++i)
r.num[i][0] = num[i][0] / b, r.num[i][1] = num[i][1] / b;
return r;
}

Matrix operator * (const Matrix &b) const{
Matrix r;
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
r.num[i][j] = (num[i][0] * b.num[0][j] % mod + num[i][1] * b.num[1][j] % mod) % mod;
return r;
}

Matrix operator ^ (int b) const{
Matrix a, r;
memcpy(a.num, num, sizeof(num));
r.num[0][0] = r.num[1][1] = 1;
for(; b; a = a * a, b >>= 1)
if(b & 1) r = r * a;
return r;
}
}X, X2;

inline int gcd(int a, int b){
return !b ? a : gcd(b, a % b);
}

inline int qpow(int a, int b){
int res = 1;
while(b){
if(b & 1) res = res * a % p;
a = a * a % p, b >>= 1;
}
return res;
}

int t;

inline int f(int n, int p){
if(n <= 1) return 1;
n--, mod = p;
Matrix F;
F.init();
F = F * (X2 ^ t);
n -= (t << 1);
if(n < 0) return F.num[0][1];
if(n > 0) F = F * X;
return F.num[0][0];
}

inline int solve(){
n = read(), p = read(), a = read(), b = read(), c = read(), d = read();
while(d){
int k = b / d;
b -= k * d, a -= k * c;
swap(a, c), swap(b, d);
}
t = n >> 1, mod = p;
int tmp = qpow(3, t);
if(!c) return (a * f(n, p) % p + b * f(n + 1, p) % p) % p * tmp % p;
if(!b) return gcd(a, c) % p * f(n, p) % p * tmp % p;
int g = gcd(f(n, b), b);
mod = g * c;
return gcd((a * f(n, mod) % mod + b * f(n + 1, mod) % mod) % mod / g, c) * g % p * tmp % p;
}

signed main(){
X.num[0][0] = 9, X.num[0][1] = 1, X.num[1][0] = 12;
X2 = X * X / 3;
T = read();
while(T--) write(solve()), puts("");
return 0;
}
// X.K.

更新于 阅读次数