用事实证明“超级无敌神仙炫酷无敌原神大王”豪华套餐不只有推式子和大ds!
第一问是简单的,记 $f_i$ 为以 $i$ 结尾的最多旧房子数,有 $$f_i=\max_{j\lt i,a_j \le a_i}{f_j+1}$$ 其中 $a_i=A_i-i$,容易用线段树维护。
考虑第二问,记 $g_i$ 为以 $i$ 结尾的最小花费,显然两个旧房子中间应该从前者开始递增建,同时要保证第一问最大,有 $$g_i=\min_{j\lt i,a_j\le a_i,f_j+1=f_i}\{g_j+\frac{(2a_j+i+j)*(i-j-1)}{2}+b_i\}$$ 其中 $b_i=A_i+B_i$。暴力转移可以拿 $40pts$。 注意到可以斜率优化,化一下式子, $$j^2+(2a_j+1)j-2g_j=2(i-1)a_j+i(i-1)+b_i-2g_i$$ 横坐标 $a_j$,纵坐标 $j^2+(2a_j+1)j-2g_j$,斜率 $2(i-1)$,维护上凸包。 然而转移条件有三个,$f_j+1=f_i$ 直接分层转移解决,剩下的是一个类似二位偏序的限制,考虑 cdq分治。 具体的,记当前转移 $f_i=d$ 的位置,当前分治区间为 $[l,r]$。考虑 $[l,mid]$ 中 $f_j=d-1$ 的位置对 $[mid+1,r]$ 中 $f_i=d$ 的位置的贡献,显然所有 $j\lt i$ 都满足,而对于 $a_j\le a_i$ 的限制,将两部分按 $a$ 升序排序后,使用双指针维护凸包即可。 时间复杂度 $O(n\log^2 n)$。记得对区间内没有有效位置的情况剪枝。
题目1859 [国家集训队2011]拆迁队
9
评论
2023-11-07 17:54:02
|
|
“超级无敌神仙炫酷无敌原神大王”豪华套餐堂堂复活。 首先树剖,考虑维护轻儿子的贡献,之后在重链上直接查。记 $f_u$ 为 $u$ 的子树中到 $u$ 的最大答案,$g_u$ 为 $u$ 的所有轻儿子中 $f_v$ 的最大值,$dis_u$ 为 $u$ 到根的距离。 询问时,在重链中往下走就维护 $g_u+dis_u$,往上走就维护 $g_u-dis_{fa_u}$,重链之间就用 $g_u$ 转移。 修改时,用类似询问的方法维护重链顶的 $f_u$,再更新 $g_{fa_u}$。考虑对每个点开一个 set 维护 $g_u$ 即可。 时间复杂度 $O(n\log^2 n)$,巨大难写。
题目1887 [国家集训队 2011] Crash的旅行计划
10
3 条 评论
2023-11-06 17:05:20
|
|
Pro3919 坡伊踹 题解CSP2023-S 模拟赛 pro1 题解贡献:rsr & lgc
题目3919 坡伊踹
4
评论
2023-10-30 13:38:45
|
|
本题另一种做法:二分图 题目描述中可知要找最小的值,即任意两个大于该值的罪犯都应该被分在两个不同的监狱,这样就可以想到二分图,先二分,将大于mid的边全部连上,直接判断二分图 如若是,则r = mid,否则l = mid+1
题目520 [NOIP 2010]关押罪犯
AAAAAAAAAA
8
评论
2023-10-27 19:00:45
|
|
__int128类型使用方法该题大整数运算部分,可以使用 __int128 类型,该类型需要 自定义输入输出,详细方法请参考如下代码: #include <bits/stdc++.h> using namespace std; typedef __int128 LL; inline read(LL &x)//输入 { x = 0; LL f = 1; char ch; if((ch = getchar()) == '-') f = -f; else x = x*10 + ch-'0'; while((ch = getchar()) >= '0' && ch <= '9') x = x*10 + ch-'0'; x *= f; } inline print(LL x)//输出 { if(x < 0) { x = -x; putchar('-'); } if(x>9) print(x/10); putchar(x%10+'0'); } int main() { LL a, b; read(a); read(b); print(a + b); return 0; }
题目3508 [NOIP 2020]排水系统
9
2 条 评论
2023-10-27 14:04:50
|
|
对于学过排序的来说是一道比较简单的题。思路:题目让给出时长最短的方法,参加之后增加的值都是1,所以先将所有活动时长从小到大排列一遍,再逐个参加, 直到满足条件为止,一下展示的是sort排序方法 #include<bits/stdc++.h>//万能头文件 using namespace std; int a[100001],b[100001],m,n,ans;//ans的值自动会为0 int main(){ freopen("bird.in","r",stdin);//freopen文件读写 freopen("bird.out","w",stdout); cin>>n>>m;//读入 for(int i=1;i<=n;i++) cin>>a[i]; sort(a,a+n);//将时长从小到大排列 for(int i=1;i<=m;i++) ans+=a[i];//加上所需时间 cout<<ans;//输出结果 return 0; }
题目3900 [桐柏邀请赛S14]bird
AAAAAAAAAA
5
评论
2023-10-19 21:12:42
|