杂题小记(2023.02.22)
杂题小记(2023.02.22)
更好的阅读体验戳此进入
好吧这一天刷了好几道大水题,大概就是写某道题的时候延申延申又延申出来一大堆奇怪的没怎么写过的小知识点,就丢到杂题里了。
HDU-3038 How Many Answers Are Wrong
题面
存在
Solution
由题意不难想到带权并查集实现,首先将闭区间转换为左闭右开区间,然后维护带权并查集的
然后 HDU 默认多测题面里不写,我还以为代码写错了找了半天。。。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N, M;
int ans(0);
class UnionFind{
private:
int fa[210000];
ll dis[210000];
public:
UnionFind(void){for(int i = 1; i <= 201000; ++i)fa[i] = i, dis[i] = 0;}
void Clear(void){for(int i = 1; i <= 201000; ++i)fa[i] = i, dis[i] = 0;}
int Find(int x){
if(x == fa[x])return x;
int cfa = fa[x];
fa[x] = Find(fa[x]);
dis[x] += dis[cfa];
return fa[x];
}
void Union(int s, int t, ll d){
int fs = Find(s), ft = Find(t);
if(fs == ft)return;
fa[fs] = ft;
dis[fs] = d + dis[t] - dis[s];
}
bool CheckDis(int s, int t, ll d){
return dis[s] != d + dis[t];
}
}uf;
int main(){
while(true){
ans = 0, uf.Clear();
N = read(), M = read();
while(M--){
int s = read(), t = read() + 1, d = read();
if(uf.Find(s) != uf.Find(t))uf.Union(s, t, d);
else ans += uf.CheckDis(s, t, d);
}printf("%d\n", ans);
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
int c = getchar();
if(!~c)exit(0);
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P1525 [NOIP2010 提高组] 关押罪犯
题面
存在 0
。
Solution
扩展域并查集。与其说扩展域并查集,也可以认为其就是利用了 2-SAT 的思想,每个点拆成两个,然后贪心地优先取更大的限制,尽量去安排即可。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N, M;
struct Node{int s, t, w;};
basic_string < Node > rels;
class UnionFind{
private:
int fa[410000];
public:
UnionFind(void){for(int i = 1; i <= 401000; ++i)fa[i] = i;}
int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
void Union(int s, int t){
int fs = Find(s), ft = Find(t);
if(fs == ft)return;
fa[fs] = ft;
}
}uf;
int main(){
N = read(), M = read();
for(int i = 1; i <= M; ++i){
int s = read(), t = read(), w = read();
rels += Node{s, t, w};
}sort(rels.begin(), rels.end(), [](const Node &a, const Node &b)->bool{return a.w > b.w;});
for(auto rel : rels){
if(uf.Find(rel.s << 1) != uf.Find(rel.t << 1))uf.Union(rel.s << 1, (rel.t << 1) | 1), uf.Union((rel.s << 1) | 1, rel.t << 1);
else printf("%d\n", rel.w), exit(0);
}printf("0\n");
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P2024 [NOI2001] 食物链
题面
存在
Solution
考虑扩展域并查集,将
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
// #define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define SON(i, x) (i + N * x)
template < typename T = int >
inline T read(void);
int N, M;
int ans(0);
class UnionFind{
private:
int fa[210000];
public:
UnionFind(void){for(int i = 1; i <= 201000; ++i)fa[i] = i;}
int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
void Union(int s, int t){
int fs = Find(s), ft = Find(t);
if(fs == ft)return;
fa[fs] = ft;
}
}uf;
int main(){
N = read(), M = read();
while(M--){
int opt = read(), s = read(), t = read();
if(s > N || t > N){++ans; continue;}
if(opt == 1){
if(
uf.Find(SON(s, 0)) == uf.Find(SON(t, 1)) ||
uf.Find(SON(s, 0)) == uf.Find(SON(t, 2)) ||
uf.Find(SON(s, 1)) == uf.Find(SON(t, 0)) ||
uf.Find(SON(s, 1)) == uf.Find(SON(t, 2)) ||
uf.Find(SON(s, 2)) == uf.Find(SON(t, 0)) ||
uf.Find(SON(s, 2)) == uf.Find(SON(t, 1))
)++ans;
else uf.Union(SON(s, 0), SON(t, 0)), uf.Union(SON(s, 1), SON(t, 1)), uf.Union(SON(s, 2), SON(t, 2));
}else{
if(s == t){++ans; continue;}
if(
uf.Find(SON(s, 0)) == uf.Find(SON(t, 0)) ||
uf.Find(SON(s, 0)) == uf.Find(SON(t, 2)) ||
uf.Find(SON(s, 1)) == uf.Find(SON(t, 1)) ||
uf.Find(SON(s, 1)) == uf.Find(SON(t, 0)) ||
uf.Find(SON(s, 2)) == uf.Find(SON(t, 2)) ||
uf.Find(SON(s, 2)) == uf.Find(SON(t, 1))
)++ans;
else uf.Union(SON(s, 0), SON(t, 1)), uf.Union(SON(s, 1), SON(t, 2)), uf.Union(SON(s, 2), SON(t, 0));
}
}printf("%d\n", ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P5787 二分图 /【模板】线段树分治
题面
在共
Solution
首先二分图可以通过扩展与并查集判断,同时并查集需要支持可撤销并进行按秩合并,对于询问进行线段树分治即可。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N, M, K;
class UnionFind{
private:
int fa[410000], siz[410000];
struct Mdf{int s; int fs; int t; int sizt;};
stack < Mdf > mdfs;
public:
UnionFind(void){for(int i = 0; i <= 401000; ++i)fa[i] = i, siz[i] = 1;}
auto GetTop(void){return mdfs.empty() ? Mdf() : mdfs.top();}
int Find(int x){return x == fa[x] ? x : Find(fa[x]);}
void Union(int s, int t){
int fs = Find(s), ft = Find(t);
if(siz[fs] > siz[ft])swap(fs, ft);
if(fs == ft)return;
mdfs.push(Mdf{fs, fa[fs], ft, siz[ft]});
siz[ft] += siz[fs];
fa[fs] = ft;
}
void Repeal(Mdf endp){
while(!mdfs.empty() && (mdfs.top().s != endp.s || mdfs.top().t != endp.t))
fa[mdfs.top().s] =mdfs.top().fs, siz[mdfs.top().t] = mdfs.top().sizt, mdfs.pop();
}
}uf;
class SegTree{
private:
struct Line{int s, t;};
basic_string < Line > tr[110000 << 2];
#define LS (p << 1)
#define RS (LS | 1)
#define MID ((gl + gr) >> 1)
public:
void Insert(int l, int r, int s, int t, int p = 1, int gl = 0, int gr = K - 1){
if(l <= gl && gr <= r)return tr[p] += Line{s, t}, void();
if(l <= MID)Insert(l, r, s, t, LS, gl, MID);
if(r >= MID + 1)Insert(l, r, s, t, RS, MID + 1, gr);
}
void dfs(int p = 1, int gl = 0, int gr = K - 1){
bool legal(true);
auto lst = uf.GetTop();
for(auto line : tr[p]){
int fs = uf.Find(line.s << 1), ft = uf.Find(line.t << 1);
if(fs == ft){
legal = false;
for(int i = gl; i <= gr; ++i)printf("No\n");
break;
}uf.Union(line.s << 1, (line.t << 1) | 1), uf.Union((line.s << 1) | 1, line.t << 1);
}
if(legal){
if(gl != gr)dfs(LS, gl, MID), dfs(RS, MID + 1, gr);
else printf("Yes\n");
}uf.Repeal(lst);
}
}st;
int main(){
N = read(), M = read(), K = read();
while(M--){
int s = read(), t = read(), l = read(), r = read() - 1;
st.Insert(l, r, s, t);
}st.dfs();
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P2627 [USACO11OPEN]Mowing the Lawn G
题面
给定序列
Solution
考虑 DP,令
预处理前缀和后有:
将
于是维护长度为
Tips:一个我调了半天的问题就是需要注意初始时应该考虑到
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N, K;
ll A[110000];
ll sum[110000];
ll dp[110000];
deque < pair < int, ll > > cur;
int main(){
N = read(), K = read();
for(int i = 1; i <= N; ++i)sum[i] = sum[i - 1] + (A[i] = read());
cur.push_back({0, 0});
for(int i = 1; i <= N; ++i){
while(!cur.empty() && cur.front().first < i - K)cur.pop_front();
while(!cur.empty() && cur.back().second < dp[i - 1] - sum[i])cur.pop_back();
cur.push_back({i, dp[i - 1] - sum[i]});
dp[i] = sum[i] + (cur.empty() ? 0 : cur.front().second);
}printf("%lld\n", dp[N]);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4954 [USACO09OPEN]Tower of Hay G
题面
存在
Solution
由于均使用的限制存在,不难想到所有方案中最优方案一定满足最底层最小。同时我们一定也需要满足尽量使高层更小,并且不难发现一般的 DP 的维度难以降低主要都是在讨论最后一层的高度等,而我们此时可以考虑将砖块逆序翻转,然后做前缀和,令其为
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N;
int w[110000];
ll s[110000];
ll F[110000], G[110000];
deque < pair < int, ll > > cur;
int main(){
N = read();
for(int i = 1; i <= N; ++i)w[i] = read();
reverse(w + 1, w + N + 1);
for(int i = 1; i <= N; ++i)s[i] = s[i - 1] + w[i];
cur.push_back({0, 0});
for(int i = 1; i <= N; ++i){
pair < int, ll > lst = {-1, -1ll};
while(!cur.empty() && cur.front().second <= s[i])lst = cur.front(), cur.pop_front();
if(~lst.first)cur.push_front(lst);
F[i] = F[cur.empty() ? 0 : cur.front().first] + 1;
G[i] = s[i] - s[cur.empty() ? 0 : cur.front().first];
while(!cur.empty() && cur.back().second > s[i] + G[i])cur.pop_back();
cur.push_back({i, s[i] + G[i]});
}printf("%lld\n", F[N]);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2023_02_22 初稿
本文作者:tsawke
本文链接:https://www.cnblogs.com/tsawke/p/17180241.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步