杂题小记(2023.02.28)更好的阅读体验戳此进入SP2713 GSS4 - Can you answer these queries IV题面SolutionCodeLG-P4391 [BOI2009]Radio Transmission 无线传输题面SolutionCodeLG-P2375 [NOI2014] 动物园题面SolutionCodeLG-P3193 [HNOI2008]GT考试题面SolutionCodeLG-P4180 [BJWC2010] 严格次小生成树题面SolutionCodeLG-P3403 跳楼机题面SolutionCodeUPD
给定序列,区间开方,区间求和。
考虑对于
xxxxxxxxxx
1071
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25template < typename T = int >
26inline T read(void);
27
28int N, M;
29ll A[110000];
30
31class SegTree{
32private:
33 ll sum[110000 << 2];
34 bool flag[110000 << 2];
35
36
37
38public:
39 void Clear(int p = 1, int gl = 1, int gr = N){
40 sum[p] = flag[p] = 0;
41 if(gl == gr)return;
42 Clear(LS, gl, MID), Clear(RS, MID + 1, gr);
43 }
44 void Pushup(int p){
45 sum[p] = sum[LS] + sum[RS];
46 flag[p] = flag[LS] & flag[RS];
47 }
48 void Build(int p = 1, int gl = 1, int gr = N){
49 if(gl == gr)return sum[p] = A[gl = gr], flag[p] = sum[p] == 0 || sum[p] == 1, void();
50 Build(LS, gl, MID), Build(RS, MID + 1, gr);
51 Pushup(p);
52 }
53 void Modify(int l, int r, int p = 1, int gl = 1, int gr = N){
54 if(gl == gr)return sum[p] = (int)sqrt(sum[p]), flag[p] = sum[p] == 0 || sum[p] == 1, void();
55 if(flag[p])return;
56 if(l <= MID)Modify(l, r, LS, gl, MID);
57 if(r >= MID + 1)Modify(l, r, RS, MID + 1, gr);
58 Pushup(p);
59 }
60 ll Query(int l, int r, int p = 1, int gl = 1, int gr = N){
61 if(l <= gl && gr <= r)return sum[p];
62 if(l > gr || r < gl)return 0;
63 return Query(l, r, LS, gl, MID) + Query(l, r, RS, MID + 1, gr);
64 }
65}st;
66
67int main(){
68 int cnt(0);
69 while(true){
70 N = read();
71 // if(!~N)exit(0);
72 printf("Case #%d:\n", ++cnt);
73 for(int i = 1; i <= N; ++i)A[i] = read < ll >();
74 st.Build();
75 M = read();
76 while(M--){
77 int opt = read();
78 if(opt == 0){
79 int l = read(), r = read();
80 st.Modify(min(l, r), max(l, r));
81 }else{
82 int l = read(), r = read();
83 printf("%lld\n", st.Query(min(l, r), max(l, r)));
84 }
85 }printf("\n");
86 st.Clear();
87 }
88 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
89 return 0;
90}
91
92template < typename T >
93inline T read(void){
94 T ret(0);
95 int flag(1);
96 char c = getchar();
97 if(c == EOF)exit(0);
98 while(c != '-' && !isdigit(c))c = getchar();
99 if(c == '-')flag = -1, c = getchar();
100 while(isdigit(c)){
101 ret *= 10;
102 ret += int(c - '0');
103 c = getchar();
104 }
105 ret *= flag;
106 return ret;
107}
给定字符串,其是由一个字符串多次重复得到的(是一个串无限重复后串的任意子串),求该字符串的最短长度。
只能说这题确实高妙!感觉推导过程和 border 的那一套理论差不多。
首先结论就是用 KMP 求出
按照类似 border 某些前置知识的证明思路证明即可,也就是考虑对于减去最长前后缀后剩下的一段,会对应着前缀末尾段,然后再对应到后缀对应段,一直对应下去,发现一定合法。
对于其一定为最优的证明,可以考虑若存在一个更小的循环节,多次循环之后最后会剩一个残块,不考虑这个残块及其影响后一定会形成一个更长前后缀,得证(这东西适合画图李姐一下,口糊肯定很抽象)。
xxxxxxxxxx
601
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25template < typename T = int >
26inline T read(void);
27
28int N;
29string S;
30int nxt[1100000];
31
32int main(){
33 N = read();
34 cin >> S;
35 int lst(0);
36 for(int i = 2; i <= N; ++i){
37 while(lst && S(lst + 1) != S(i))lst = nxt[lst];
38 if(S(lst + 1) == S(i))++lst;
39 nxt[i] = lst;
40 }printf("%d\n", N - nxt[N]);
41
42 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
43 return 0;
44}
45
46template < typename T >
47inline T read(void){
48 T ret(0);
49 int flag(1);
50 char c = getchar();
51 while(c != '-' && !isdigit(c))c = getchar();
52 if(c == '-')flag = -1, c = getchar();
53 while(isdigit(c)){
54 ret *= 10;
55 ret += int(c - '0');
56 c = getchar();
57 }
58 ret *= flag;
59 return ret;
60}
给定字符串
想麻烦了,找了半天性质,实际上很简单。
首先不考虑重叠,对于一般的求数量我们只需要在求
xxxxxxxxxx
761
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25
26template < typename T = int >
27inline T read(void);
28
29string S;
30int nxt[1100000];
31int num[1100000];
32
33int main(){
34 int T = read();
35 while(T--){
36 ll ans(1);
37 cin >> S;
38 int N = S.length();
39 int lst(0);
40 nxt[0] = nxt[1] = num[0] = 0, num[1] = 1;
41 for(int i = 2; i <= N; ++i){
42 while(lst && S(lst + 1) != S(i))lst = nxt[lst];
43 if(S(lst + 1) == S(i))++lst;
44 nxt[i] = lst, num[i] = num[lst] + 1;
45 }lst = 0;
46 for(int i = 2; i <= N; ++i){
47 while(lst && S(lst + 1) != S(i))lst = nxt[lst];
48 if(S(lst + 1) == S(i))++lst;
49 while(lst > (i >> 1))lst = nxt[lst];
50 (ans *= (num[lst] + 1)) %= MOD;
51 }
52 // int same(1);
53 // while(same + 1 <= N && S(same + 1) == S(same))++same;
54 // ll ans(1);
55 // for(int i = 1; i <= N; ++i)(ans *= nxt[i] ? (S(1) == S(i) ? min(nxt[i] + 1, same + 1) : 2) : 1) %= MOD;
56 printf("%lld\n", ans);
57 }
58 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
59 return 0;
60}
61
62template < typename T >
63inline T read(void){
64 T ret(0);
65 int flag(1);
66 char c = getchar();
67 while(c != '-' && !isdigit(c))c = getchar();
68 if(c == '-')flag = -1, c = getchar();
69 while(isdigit(c)){
70 ret *= 10;
71 ret += int(c - '0');
72 c = getchar();
73 }
74 ret *= flag;
75 return ret;
76}
求长度为
首先按照一般思路考虑一个朴素 DP,即令
显然可以等效写成:
发现其满足矩阵形式,且
对于
xxxxxxxxxx
1071
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25
26template < typename T = int >
27inline T read(void);
28
29int N, M, K;
30string S;
31int nxt[30];
32int G[30][30];
33
34class Matrix{
35private:
36public:
37 int v[20][20];
38 Matrix(void){memset(v, 0, sizeof v);}
39 friend Matrix operator * (const Matrix &a, const Matrix &b){
40 Matrix ret;
41 for(int i = 0; i < M; ++i)
42 for(int j = 0; j < M; ++j)
43 for(int k = 0; k < M; ++k)
44 (ret.v[i][j] += a.v[i][k] * b.v[k][j] % MOD) %= MOD;
45 return ret;
46 }
47 void Print(void){
48 printf("Matrix:\n");
49 for(int i = 0; i < M; ++i)
50 for(int j = 0; j < M; ++j)
51 printf("%d%c", v[i][j], j == M - 1 ? '\n' : ' ');
52 }
53}base, ans;
54
55Matrix qpow(Matrix a, ll b){
56 Matrix ret, mul(a);
57 for(int i = 0; i < M; ++i)ret.v[i][i] = 1;
58 while(b){
59 if(b & 1)ret = ret * mul;
60 b >>= 1;
61 mul = mul * mul;
62 }return ret;
63}
64
65int main(){
66 N = read(), M = read(), K = read();
67 cin >> S;
68 int lst(0);
69 for(int i = 2; i <= M; ++i){
70 while(lst && S(lst + 1) != S(i))lst = nxt[lst];
71 if(S(lst + 1) == S(i))++lst;
72 nxt[i] = lst;
73 }
74 for(int i = 0; i < M; ++i)
75 for(int j = '0'; j <= '9'; ++j){
76 int lst = i;
77 while(lst && S(lst + 1) != j)lst = nxt[lst];
78 if(S(lst + 1) == j)++lst;
79 ++G[i][lst];
80 }
81 for(int i = 0; i < M; ++i)
82 for(int j = 0; j < M; ++j)
83 base.v[i][j] = G[i][j] % MOD;
84 ans.v[0][0] = 1;
85 ans = ans * qpow(base, N);
86 int rans(0);
87 for(int i = 0; i < M; ++i)(rans += ans.v[0][i]) %= MOD;
88 printf("%d\n", rans);
89 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
90 return 0;
91}
92
93template < typename T >
94inline T read(void){
95 T ret(0);
96 int flag(1);
97 char c = getchar();
98 while(c != '-' && !isdigit(c))c = getchar();
99 if(c == '-')flag = -1, c = getchar();
100 while(isdigit(c)){
101 ret *= 10;
102 ret += int(c - '0');
103 c = getchar();
104 }
105 ret *= flag;
106 return ret;
107}
求连通图的严格次小生成树。
存在如下方法,正确性可感性理解,理性证明未知。
考虑任意建出一棵 MST,然后枚举所有没有在 MST 中的边,分别找出每条边的
对于维护可以考虑用树剖 + 线段树,边权下放到点权,然后合并时可以强行讨论,也可无脑开 basic_string
排序后 unique
实现,此写法常数较大但可以通过。
xxxxxxxxxx
1821
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template < typename T = int >
24inline T read(void);
25
26int N, M;
27struct Edge{
28 Edge* nxt;
29 int to;
30 int val;
31 OPNEW;
32}ed[210000];
33ROPNEW;
34Edge* head[110000];
35
36class UnionFind{
37private:
38 int fa[110000];
39public:
40 UnionFind(void){for(int i = 0; i <= 101000; ++i)fa[i] = i;}
41 int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
42 void Union(int s, int t){int fs = Find(s), ft = Find(t); fa[fs] = ft;}
43}uf;
44
45struct Edg{int s, t, v;};
46basic_string < Edg > edgs;
47basic_string < Edg > trash;
48
49int dep[110000], fa[110000], hson[110000], siz[110000], dfn[110000], idx[110000], top[110000];
50
51void dfs_pre(int p = 1, int fa = 0){
52 ::fa[p] = fa, dep[p] = dep[fa] + 1, siz[p] = 1;
53 for(auto i = head[p]; i; i = i->nxt){
54 if(SON == fa)continue;
55 dfs_pre(SON, p);
56 siz[p] += siz[SON];
57 if(siz[SON] > siz[hson[p]])hson[p] = SON;
58 }
59}
60void dfs_make(int p = 1, int top = 1){
61 static int cdfn(0);
62 dfn[p] = ++cdfn, idx[cdfn] = p, ::top[p] = top;
63 if(hson[p])dfs_make(hson[p], top);
64 for(auto i = head[p]; i; i = i->nxt)
65 if(SON != fa[p] && SON != hson[p])dfs_make(SON, SON);
66}
67
68ll ans(LONG_LONG_MAX);
69int val[110000];
70
71void PushdownVal(int p = 1, int fa = 0){
72 for(auto i = head[p]; i; i = i->nxt)
73 if(SON != fa)
74 val[SON] = i->val, PushdownVal(SON, p);
75}
76
77class SegTree{
78private:
79 int mx[110000 << 2], mx2[110000 << 2];
80
81
82
83public:
84 SegTree(void){memset(mx, -1, sizeof mx), memset(mx2, -1, sizeof mx2);}
85 void Pushup(int p){
86 basic_string < int > vals;
87 if(~mx[LS])vals += mx[LS];
88 if(~mx[RS])vals += mx[RS];
89 if(~mx2[LS])vals += mx2[LS];
90 if(~mx2[RS])vals += mx2[RS];
91 sort(vals.begin(), vals.end(), greater < int >());
92 vals.erase(unique(vals.begin(), vals.end()), vals.end());
93 mx[p] = (int)vals.size() >= 1 ? *vals.begin() : -1;
94 mx2[p] = (int)vals.size() >= 2 ? *next(vals.begin()) : -1;
95 }
96 void Build(int p = 1, int gl = 1, int gr = N){
97 if(gl == gr)return mx[p] = val[idx[gl = gr]], void();
98 Build(LS, gl, MID), Build(RS, MID + 1, gr);
99 Pushup(p);
100 }
101 pair < int, int > Query(int l, int r, int p = 1, int gl = 1, int gr = N){
102 if(l <= gl && gr <= r)return {mx[p], mx2[p]};
103 if(l > gr || r < gl)return {-1, -1};
104 basic_string < int > vals;
105 auto ret = Query(l, r, LS, gl, MID);
106 if(~ret.first)vals += ret.first;
107 if(~ret.second)vals += ret.second;
108 ret = Query(l, r, RS, MID + 1, gr);
109 if(~ret.first)vals += ret.first;
110 if(~ret.second)vals += ret.second;
111 sort(vals.begin(), vals.end(), greater < int >());
112 vals.erase(unique(vals.begin(), vals.end()), vals.end());
113 return {(int)vals.size() >= 1 ? *vals.begin() : -1, (int)vals.size() >= 2 ? *next(vals.begin()) : -1};
114 }
115}st;
116
117ll origin(0);
118
119int QueryMx2(int s, int t, int ban){
120 basic_string < int > vals;
121 while(top[s] != top[t]){
122 if(dep[top[s]] < dep[top[t]])swap(s, t);
123 auto ret = st.Query(dfn[top[s]], dfn[s]);
124 if(~ret.first)vals += ret.first;
125 if(~ret.second)vals += ret.second;
126 // printf("Querying %d->%d, [%d, %d], ret %d %d\n", top[s], s, dfn[top[s]], dfn[s], ret.first, ret.second);
127 s = fa[top[s]];
128 }if(dep[s] < dep[t])swap(s, t);
129 auto ret = st.Query(dfn[hson[t]], dfn[s]);
130 // printf("Querying %d->%d, [%d, %d], ret %d %d\n", hson[t], s, dfn[hson[t]], dfn[s], ret.first, ret.second);
131 if(~ret.first)vals += ret.first;
132 if(~ret.second)vals += ret.second;
133 sort(vals.begin(), vals.end(), greater < int >());
134 vals.erase(unique(vals.begin(), vals.end()), vals.end());
135 int mx = (int)vals.size() >= 1 ? *vals.begin() : -1, mx2 = (int)vals.size() >= 2 ? *next(vals.begin()) : -1;
136 return mx != ban ? mx : mx2;
137}
138
139int main(){
140 N = read(), M = read();
141 for(int i = 1; i <= M; ++i){
142 int s = read(), t = read(), v = read();
143 if(s == t)continue;
144 edgs += Edg{s, t, v};
145 }sort(edgs.begin(), edgs.end(), [](const Edg &a, const Edg &b)->bool{return a.v < b.v;});
146 for(auto edg : edgs){
147 auto [s, t, v] = edg;
148 if(uf.Find(s) != uf.Find(t))
149 head[s] = new Edge{head[s], t, v},
150 head[t] = new Edge{head[t], s, v},
151 origin += v,
152 uf.Union(s, t);
153 else trash += edg;
154 }dfs_pre(), dfs_make(), PushdownVal();
155 st.Build();
156 // printf("origin is %lld\n", origin);
157 for(auto edg : trash){
158 auto [s, t, v] = edg;
159 int ret = QueryMx2(s, t, v);
160 if(!~ret)continue;
161 // printf("[%d - %d], v = %d, ret = %d\n", s, t, v, ret);
162 ans = min(ans, origin - ret + v);
163 }printf("%lld\n", ans);
164 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
165 return 0;
166}
167
168template < typename T >
169inline T read(void){
170 T ret(0);
171 int flag(1);
172 char c = getchar();
173 while(c != '-' && !isdigit(c))c = getchar();
174 if(c == '-')flag = -1, c = getchar();
175 while(isdigit(c)){
176 ret *= 10;
177 ret += int(c - '0');
178 c = getchar();
179 }
180 ret *= flag;
181 return ret;
182}
给定
经典同余最短路问题,令
xxxxxxxxxx
861
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template < typename T = int >
24inline T read(void);
25
26ll H;
27int x, y, z;
28
29struct Edge{
30 Edge* nxt;
31 int to;
32 int val;
33 OPNEW;
34}ed[210000];
35ROPNEW;
36Edge* head[110000];
37
38bitset < 110000 > vis;
39ll dis[110000];
40ll ans(0);
41
42void Dijkstra(void){
43 memset(dis, 0x3f, sizeof dis);
44 static priority_queue < pair < ll, int >, vector < pair < ll, int > >, greater < pair < ll, int > > > cur;
45 dis[1] = 1, cur.push({0, 1});
46 while(!cur.empty()){
47 int p = cur.top().second; cur.pop();
48 if(vis[p])continue;
49 vis[p] = true;
50 for(auto i = head[p]; i; i = i->nxt)
51 if(dis[p] + i->val < dis[SON])
52 dis[SON] = dis[p] + i->val, cur.push({dis[SON], SON});
53 }
54}
55
56int main(){
57 H = read < ll >();
58 x = read(), y = read(), z = read();
59 if(x == 1 || y == 1 || z == 1)printf("%lld\n", H), exit(0);
60 for(int i = 0; i < x; ++i)
61 head[i] = new Edge{head[i], (i + y) % x, y},
62 head[i] = new Edge{head[i], (i + z) % x, z};
63 Dijkstra();
64 for(int i = 0; i < x; ++i)
65 if(H >= dis[i])
66 ans += (H - dis[i]) / x + 1;
67 printf("%lld\n", ans);
68 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
69 return 0;
70}
71
72template < typename T >
73inline T read(void){
74 T ret(0);
75 int flag(1);
76 char c = getchar();
77 while(c != '-' && !isdigit(c))c = getchar();
78 if(c == '-')flag = -1, c = getchar();
79 while(isdigit(c)){
80 ret *= 10;
81 ret += int(c - '0');
82 c = getchar();
83 }
84 ret *= flag;
85 return ret;
86}
update-2023_02_28 初稿