JZOJ 2020.07.30【NOIP提高组】模拟
总结
本场比赛很不负责对待
暴力都没怎么打
一个半小时后才开始打题
很悲剧的只有 分
4300. 装饰大楼
题目
略
思路
很无聊的找规律题
考场弃疗
#include<cstdio> #include<iostream> using namespace std; typedef long long LL; const int N = 1e6 + 5; int n , a[N] , s , x , t; LL ans; int main() { freopen("building.in" , "r" , stdin); freopen("building.out" , "w" , stdout); scanf("%d" , &n); for(register int i = 1; i < n; i++) scanf("%d" , &a[i]); for(register int i = 1; i < n; i++) { ans += (LL)s + 1; if (a[i] <= s + 1) ans--; s = max(s , a[i]); } ans += (LL)s + 1; s = 0; for(register int i = 1; i < n; i++) { if (a[i] - x > 2) { printf("0"); return 0; } else if (a[i] - x == 2) { s++; if (s == 1) t = i; } if (s >= 2) { printf("0"); return 0; } x = max(x , a[i]); } if (s == 1) { x = s = 0; for(register int i = 1; i < t; i++) if (a[i] > x) x = a[i] , s = i; ans = t - s; } printf("%lld" , ans); }
4301. 备用钥匙
题目
略
思路
奇怪的 题
很容易想到按时间排序
相邻两个时间分离开和回来四种情况讨论
不用钥匙的直接加,记到 里
单独用一个钥匙的另开数组记需要钥匙者产生的贡献,记到 里
两个都需要就弄出链来并算给他们两把钥匙能获得的贡献,记到 里
然后调整 的顺序
链上的连在一起
设 表示前 中选 个人且强行让 也持有钥匙的最大答案,
那么转移:
最终
#include<cstdio> #include<algorithm> using namespace std; const int N = 2005; int n , m , k , tot , s[N] , se[N] , sz[N] , c[N] , ans , pre[N] , nxt[N] , f[N][N] , g[N][N] , vis[N] , b[N]; struct node{ int id , t , s; }a[2 * N]; inline bool cmp(node x , node y){return x.t < y.t;} int main() { freopen("key.in" , "r" , stdin); freopen("key.out" , "w" , stdout); scanf("%d%d%d" , &n , &m , &k); int p , q; for(register int i = 1; i <= n; i++) { scanf("%d%d" , &p , &q); a[++tot].id = i , a[tot].t = p , a[tot].s = 1; a[++tot].id = i , a[tot].t = q , a[tot].s = 2; } sort(a + 1 , a + tot + 1 , cmp); ans = a[1].t + m - a[tot].t; for(register int i = 1; i <= tot; i++) { if (a[i].s == 2 && a[i + 1].s == 1) ans += a[i + 1].t - a[i].t; if (a[i].id == a[i + 1].id) s[a[i].id] += a[i + 1].t - a[i].t; else if (a[i].s == 1 && a[i + 1].s == 1) s[a[i].id] += a[i + 1].t - a[i].t; else if (a[i].s == 2 && a[i - 1].s == 2) s[a[i].id] += a[i].t - a[i - 1].t; else if (a[i].s == 1 && a[i + 1].s == 2) { pre[a[i + 1].id] = a[i].id; nxt[a[i].id] = a[i + 1].id; sz[a[i + 1].id] = a[i + 1].t - a[i].t; } } int to; tot = 0; for(register int i = 1; i <= n; i++) if (!vis[i]) { to = i; while (pre[to]) to = pre[to]; while (to) b[++tot] = to , vis[to] = 1 , to = nxt[to]; } for(register int i = 1; i <= n; i++) c[i] = s[b[i]] , se[i] = sz[b[i]]; f[1][1] = g[1][1] = c[1]; for(register int i = 2; i <= n; i++) { g[i][1] = max(g[i - 1][1] , f[i][1] = c[i]); for(register int j = 2; j <= k; j++) g[i][j] = max(g[i - 1][j] , f[i][j] = max(f[i - 1][j - 1] + se[i] , g[i - 2][j - 1]) + c[i]); } printf("%d" , ans + g[n][k]); }
4302. IOIOI卡片占卜
题目
略
思路
牛逼得不得了的操作:记给定的序列 为 , 为 。让这个序列相邻两个异或
于是区间 翻转变为异或单点 和 (亲手模拟看看)
异或后的序列只剩 个 ,让这四个 变 的最少代价即为答案
那么我们把 和 连边,边权为 ,表示 到 的最小代价为
因为一次翻一个区间,即转化后的一次翻两个点,所以现在要使 个 配对
使他们最短路的和最小即为答案
#include<cstdio> #include<queue> #include<iostream> #include<cstring> using namespace std; typedef long long LL; const int N = 5e5 + 5; int a , b , c , d , e , vis[N] , h[N] , tot , n; LL dis[N] , ans; struct edge{ int nxt , to , w; }E[2 * N]; struct node{ int id; LL d; bool operator < (node c) const { return d > c.d; } }; inline void add(int x , int y , int z) { E[++tot].to = y; E[tot].w = z; E[tot].nxt = h[x]; h[x] = tot; } priority_queue<node> Q; inline LL dij(int s , int t) { memset(vis , 0 , sizeof vis); memset(dis , 60 , sizeof dis); while (!Q.empty()) Q.pop(); dis[s] = 0; Q.push((node){s , dis[s]}); node x; while (!Q.empty()) { x = Q.top(); Q.pop(); if (vis[x.id]) continue; vis[x.id] = 1; if (x.id == t) break; for(register int i = h[x.id]; i; i = E[i].nxt) { int v = E[i].to; if (dis[x.id] + E[i].w < dis[v]) { dis[v] = dis[x.id] + E[i].w; Q.push((node){v , dis[v]}); } } } return dis[t]; } int main() { freopen("card.in" , "r" , stdin); freopen("card.out" , "w" , stdout); scanf("%d%d%d%d%d" , &a , &b , &c , &d , &e); scanf("%d" , &n); int l , r; for(register int i = 1; i <= n; i++) { scanf("%d%d" , &l , &r); l--; add(l , r , r - l) , add(r , l , r - l); } ans = min(dij(a , a + b) + dij(a + b + c , a + b + c + d) , dij(a , a + b + c) + dij(a + b , a + b + c + d)); ans = min(ans , dij(a , a + b + c + d) + dij(a + b , a + b + c)); if (ans >= 4340410370284600380) printf("-1"); else printf("%lld" , ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具