Processing math: 100%

省选测试47


又差不多是0分,两天加起来总共8分,我也是没谁了
T1又写出正解,没用c++11编译,于是CE了,T3看不懂题,找了huge,解释错了之后我就40变0分,
T2的n2很好像,可惜实在是没时间想了,于是写了个最裸的暴力,成为两天里唯一的得分点

A 旅游#

题目大意 : 要从x到y,每次最多走到后面第z个城市,走每个城市都会付出a的代价,走某些城市会有收益,问到终点的最大收益

  • n2的dp很好想,设f[i]为走到第i个有收益的城市所得的最大收益,转移也就很显然

f[i]=i1maxj=0f[j]+wpos[i]pos[j]z

  • 想斜率优化,发现这个值关于pos[i]的函数是每z个都是平的,然后降a,然后z个不变,然后降a这样,不是很能斜率优化

  • 于是我把他们都表示在1到z里,然后只取有用的(就是最上面的),set维护,查询的时候在set里二分,写起来很鬼畜

  • 正解思路和我我差不多,只是他是用线段树维护,常数较大

Code#

Show Code
Copy
#include <set> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 1e5 + 5; int read(int x = 0, int f = 1, char c = getchar()) { for (; (c < '0' || c > '9'); c = getchar()) if (c == '-') f = -1; for (;!(c < '0' || c > '9'); c = getchar()) x = x * 10 + c - '0'; return x * f; } int s, t, k, m, n, a[N], w[N]; set< pair<int, ll> > st; set< pair<int, ll> > ::iterator it1, it2; ll f[N], ans; ll Cal(int x) { if (!x) return 0; int a = (x - 1) / k, b = x - a * k; return (st.lower_bound(make_pair(b, -1e18)) -> second) - 1ll * a * m; } void Insert(int x, ll w) { if (!x) x = k, w -= m; int a = (x - 1) / k, b = x - a * k; pair<int, ll> tmp = make_pair(b, w + 1ll * a * m); st.insert(tmp); it1 = st.lower_bound(tmp); it2 = ++it1; --it1; if (it2 != st.end()) { if ((it2 -> second) > (it1 -> second)) return st.erase(it1), void(); } while (it1 != st.begin()) { it2 = --it1; ++it1; if ((it2 -> second) < (it1 -> second)) st.erase(it2); else break; } } int main() { freopen("tourist.in", "r", stdin); freopen("tourist.out", "w", stdout); s = read(); t = read() - s; k = read(); m = read(); n = read(); Insert(k, -m); for (int i = 1; i <= n; ++i) { int p = read() - s, w = read(); ll tmp = Cal(p) + w; Insert(p, tmp); Insert(((p - 1) / k + 1) * k, tmp - m); } printf("%lld\n", Cal(t)); return 0; }

B 宝石 (Unaccepted)#

题目大意 : n颗宝石,可以有D种颜色,问有多少种方案可以满足找到至少m组颜色相同的宝石,不能重复选

  • 生成函数

Code#

Show Code
Copy

C 线段#

题目大意 : 有n条线段,第i条连接点i和i+1,动态修改线段断不断,询问两点共有多长的时间的联通的

  • 把询问的y减1,可以转换成求x到y线段状态全是1的时刻有多少个,将每个询问x,y对应到二维平面上的一个点

  • 考虑改变第x个点的状态会对哪些询问造成影响

  • 设l,r为从x向左右延伸,全是1的极大区间的左右端点,发现左端点在[l,x],右端点在[x,r]内的点都会被影响

  • 转换到二维平面上就是左下角为(l,x),右上角为(x,r)的区间会受到影响

  • 所以,当时间为i的修改使x断开,就将受影响的区间都加上一个i,使x链接的话就给区间减去i

  • 对于时间为i个询问(x,y+1),设(x,y)点的值为ans,如果x,y之间全是1,就是ans+i,因为在连接的时候减去了个j,所以要+i,如果不全是1的话就直接是ans

  • 现在问题就转换成了在二维平面上区间加,单点查,可以kdtree,cdq,二维线段树,不过树状数组套动态开点线段树好写,跑得的也快

  • 写树状数组套动态开点线段树的话,就得变差分了,

  • 要给一个左下角为(l,x),右上角为(x,r)的区间加上w,就给(l,x)+w,(x+1,r+1)+w,(x+1,x)-w,(l,r+1)-w

  • 单点查询就要查差分数组的前缀和就好了

Code#

Show Code
Copy
#include <set> #include <cstdio> #define ls t[rt].l #define rs t[rt].r using namespace std; const int N = 3e5 + 5; int read(int x = 0, int f = 1, char c = getchar()) { for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0'; return x * f; } char c[N]; set<int> s; set<int> ::iterator it; int n, m, rt[N], trc; struct Tree { int s, l, r; }t[N*72]; void Add(int &rt, int l, int r, int x, int w) { if (!rt) rt = ++trc; t[rt].s += w; if (l == r) return; int mid = l + r >> 1; if (x <= mid) Add(ls, l, mid, x, w); else Add(rs, mid + 1, r, x, w); } void Add(int x, int y, int w) { for (; x <= n; x += x & -x) Add(rt[x], 1, n, y, w); } int Ask(int rt, int l, int r, int x) { if (r <= x) return t[rt].s; int mid = l + r >> 1, ans = 0; if (ls) ans = Ask(ls, l, mid, x); if (rs && x > mid) ans += Ask(rs, mid+1, r, x); return ans; } int Ask(int x, int y, int ans = 0) { for (; x; x -= x & -x) ans += Ask(rt[x], 1, n, y); return ans; } int main() { freopen("segment.in", "r", stdin); freopen("segment.out", "w", stdout); n = read(), m = read(); scanf("%s", c + 1); s.insert(0); s.insert(++n); for (int i = 1; i <= n; ++i) { c[i] -= '0'; if (!c[i]) s.insert(i); } for (int i = 1; i <= m; ++i) { char od; scanf(" %c", &od); int x = read(); if (od == 't') { int l = x, r = x; it = s.lower_bound(x); if (*it == x) ++it; r = *it-1; if (*(--it) == x) --it; l = *it+1; if (c[x] ^= 1) { s.erase(x); Add(l, x, -i), Add(x + 1, x, i); Add(l, r + 1, i), Add(x + 1, r + 1, -i); } else { s.insert(x); Add(l, x, i), Add(x + 1, x, -i); Add(l, r + 1, -i), Add(x + 1, r + 1, i); } } else { int y = read() - 1, ans = Ask(x, y); it = s.lower_bound(x); if (it != s.end() && *it <= y) printf("%d\n", ans); else printf("%d\n", ans + i); } } return 0; }
posted @   Shawk  阅读(48)  评论(0编辑  收藏  举报
编辑推荐:
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
阅读排行:
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Huawei LiteOS基于Cortex-M4 GD32F4平台移植
· mysql8.0无备份通过idb文件恢复数据过程、idb文件修复和tablespace id不一致处
点击右上角即可分享
微信分享提示
CONTENTS