9.22 小记

[COCI2019-2020#5] Putovanje

tag:树上差分

先处理出从 1 到 n 依次走完每条边会走多少次。然后对于每条边都看一下是买单程票还是多程票划算,统计一下就行了

[COCI2019-2020#5] Zapina

首先需要看清楚题面

然后就做出来了。

\(f_{i,j}\) 为给前 \(i\) 人分配了前 \(j\) 道题至少一个人开心的的方案数。

假设 \(i\) 开心:\(f_{i,j}=C_{j}^i\times (i-1)^{j-i}\)

假设 \(i\) 不开心:\(f_{i,j}=\sum _{k=0,k\not = i} f_{i-1,j-k}\times C_{j}^{k}\)

CF916E Jamie and Tree

哇是个厉害的分类讨论题!

其实之后的如果又说树上的换根问题的,都可以直接套这种分类讨论的结果

假设我们要操作的点为 \(x\) ,当前确定的根为 \(rt\) 。我们的操作都是对于子树操作,然后我们分如下几种情况讨论(查询和修改都差不多):

  1. \(x\)\(rt\) 重合: 只需要操作整棵树就可以了
  2. \(rt\) 不在 \(x\) 的子树内:\(x\) 的子树还是它自己
  3. \(rt\)\(x\) 的子树内:这种情况有点麻烦。可以发现其实是整棵树刨除 \(x\)\(rt\) 路径上最靠近 \(x\) 的节点的子树。(嗯就自己画一画就知道了)找到这个节点可以用倍增。

然后这道题还要求 \(lca\)

还是分几种情况

  1. \(x\)\(y\) 在原树上都在根的子树内:\(lca\) 就是 \(x\)\(y\)\(lca\)
  2. \(x\)\(y\) 一个在子树内,另一个在子树外:显然根就是 \(lca\)
  3. \(x\)\(y\) 都在子树外:设 \(p=LCA(x,rt),q=LCA(y,rt)\)\(p\)\(q\) 的深度更大的那个

然后对于 \(x,y\)\(lca\) ,我们只需要求 \(LCA(x,rt),LCA(y,rt),LCA(x,y)\) 的深度更大的那个。

[CSP-S2019] 划分

我不行了,不到为啥,现在好困啊

困麻了

这题的话,更像是用一些决策单调性?

\(O(n^3)\) 的 dp 还是很好想的吧

然后还有一个显而易见的结论:\((a+b)^2\geq a^2+b^2\) ,所以在能保证性质的情况下,最后一段要尽可能的小,如果你找到 \(f_j\) 转移到 \(f_i\) 的最优决策点 \(k\),那么 $f_{j-1} $ 到 \(f_i\) 的最优决策点一定在 \(k\) 左边一个尽可能近的位置。 这样是 \(O(n^2)\) 的(64 pts)

然后考虑继续优化。设 \(s_i\) 为到 $i $ 的前缀和。如果 \(i\sim j\) 可以转移的话, \(s_i-s_j\geq s_j-s_{lst_j}\)\(lst\) 代表对于某一点的最优决策点。化简一下得到 \(2s_j-s_{lst_j}\leq s_i\),这样我们就把与 \(j\) 有关的东西扔到一起啦!这样就是单调队列可以优化的形式。单调队列可以这样优化是因为 \(s_i\) 单调递增,无法成为 \(i\) 的决策的点一定无法成为 \(i+1\) 的决策,所以决策点一定是单调递增的。

然后细节上的话,不要用 __int128 开数组,会炸的。但是19年根本就不让用啊

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1<<30;
const int maxn=40000002;
int n;int a[maxn],b[maxn];
int  p[100002],l[100002],r[100002];
void init(int typ)
{
	if(!typ)for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	else 
	{
		int x,y,z,m;scanf("%d%d%d%d%d%d",&x,&y,&z,&b[1],&b[2],&m);
		for(int i=1;i<=m;i++) scanf("%d%d%d",&p[i],&l[i],&r[i]);
		for(int i=3;i<=n;i++) b[i]=((ll)x*b[i-1]+(ll)y*b[i-2]+z)%mod;
		for(int j=1;j<=m;j++)
		{
			for(int i=p[j-1]+1;i<=p[j];i++)
				a[i]=(b[i]%(r[j]-l[j]+1))+l[j];
		}
	}
}
int q[maxn];int lst[maxn];
ll s[maxn];ll g(int x){return 2*s[x]-s[lst[x]];}
template<typename _T>
void write(_T x)
{
	if(x<0) {putchar('-');x=-x;}
	if(x>9) write(x/10);
	putchar(x%10+'0');	
}
int main()
{
	int typ;scanf("%d%d",&n,&typ);
	init(typ);
	for(int i=1;i<=n;i++)
		s[i]=s[i-1]+a[i];
	int L=1,R=0;q[++R]=0;
	for(int i=1;i<=n;i++)
	{
		while(R>L&&g(q[L+1])<=s[i]) L++; //要找到最靠后的合法的解 
		lst[i]=q[L];
		while(R>=L&&g(q[R])>=g(i)) R--;// g越小越容易成为决策,所以让队列单调递增
		q[++R]=i;
	}
	__int128 xx=0;
	for(int i=n;i>0;i=lst[i])
	{
		xx+=(__int128)(s[i]-s[lst[i]])*(s[i]-s[lst[i]]);
	}	
	write(xx);
}

[SBCOI2020] 一直在你身旁

就好难想的单调队列 awa

对于 \(O(n^3)\) 的就是区间 DP ,设 \(f_{i,j}\) 表示如果已经确定答案在 \(i\sim j\) 的范围内,确定具体的答案需要的最小花费。

\(f_{i,j}=\min\{\max\{f_{i,k},f_{k+1,j}\}+a_k\}\)

含义就是要找到一个点能将区间分成两段,来确定答案在哪一边,然后取两边的 \(\max\) 是考虑最坏情况。

然后考虑怎样优化。

可以发现, \(f_{i,k}\) 随着 \(k\) 的增大而增大,\(f_{k+1,j}\) 随着 \(k\) 的增大而减小。于是对于 \([i,j]\) ,一定有一个分割点使得在 \(K\) 左边的 \(k\) 都是 \(f_{k+1,j}\) 更大,右边的 \(k\) 都是 \(f_{i,k}\) 更大一点 。所以我们要找一下这个分割点。

然后我们可以发现,当 \(r\) 固定时,\(l\) 越往左,\(K\) 也越往左。(还挺好理解的吧)所以我们可以先枚举 \(r\) ,再从大到小枚举 \(l\) ,用一个标记指针就能找到分割点了。

然后是怎么找左右两侧的贡献。

考虑 \(f_{i,k}>f_{k+1,j}\) 的情况,\(f_{i,k}+a_k\) 会成为答案,发现 \(f_{i,k}+a_k\) 一定单调递增,所以只需要取最左面能取到的 \(k\) 就行了

考虑 \(f_{i,k}\leq f_{k+1,j}\) 的情况,这次\(f_{k+1,j}+a_k\)不一定单调递减,但 \(f_{k+1,j}+a_k\)\(r\) 固定时只和 \(k\) 有关,需要维护一个单调队列来维护出最小值。

#include <bits/stdc++.h>
using namespace std;
const int maxn=8002;
typedef long long ll;
int n;ll a[maxn];
ll f[maxn][maxn];
int q[maxn];
int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		for(int r=2;r<=n;r++)
		{
			int L=1,R=1;q[L]=r;int k=r;
			f[r-1][r]=a[r-1];f[r][r]=0;
			for(int l=r-2;l>=1;l--)
			{
				while(k>l&&f[l][k-1]>f[k][r]) k--;
				f[l][r]=f[l][k]+a[k];
				while(L<=R&&q[L]>=k) L++;
				if(L<=R) f[l][r]=min(f[l][r],f[q[L]+1][r]+a[q[L]]);
				while(L<=R&&f[q[R]+1][r]+a[q[R]]>=f[l+1][r]+a[l])
					R--;
				q[++R]=l;
			}
		}	
		printf("%lld\n",f[1][n]);
	}
}

困麻了

废话

昨天做了个噩梦,梦见被亲人追杀(?)

反正是梦很长很长,梦里的我都累了,醒来的我更累,感觉像根本没睡

然后下午几乎睁不开眼睛

不管了,今天好好休息

成 为不了光鲜模样 就无法悲伤

面 对不了真实自我 就不必逞强

不堪的独白 被负罪感割开

抹消 我存在 的意外

解脱我 仅剩一丝色彩

不明白 潦草的结局 封锁角色

不安 飘荡在 决策以外

posted @ 2022-09-24 14:55  cc0000  阅读(35)  评论(0编辑  收藏  举报