2024-03-07

2024-03-07

做题

埃及分数

迭代加深搜索

两层迭代:单位分数的个数 \(depth\) 和最大的分母 \(mxs\)
推枚举的当前分母 \(p\) 的上下界:

  • \(\frac{1}{p}\le \frac{a}{b}\)\(p \ge \frac{b}{a}\)
  • 每一个单位分母不相同,所以 \(p \ge last\)
  • 要在后面 \(depth-k+1\) 个分数凑出当前的 \(\frac{a}{b}\) 每个最大是 \(\frac{1}{p}\),所以

\[\frac{depth-k+1}{p} \ge \frac{a}{b} \]

\[p \le \frac{b\times (depth-k+1)}{a} \]

  • 要保证当前选了 \(p\) 之后,剩下的 \(depth-k\) 个单位分数还有的选,即

\[\frac{a}{b} - \frac{1}{p} \ge \frac{depth-k}{mxs} \]

解得

\[p \ge \frac{b\times mxs}{a\times mxs-b\times (depth-k)} \]

综上

\[p\in [\max(last,\frac{b\times mxs}{a\times mxs-b\times (depth-k)},\frac{b}{a}),\min(S,\frac{b\times (depth-k+1)}{a})] \]

还有优化:只剩最后两个分数的时候 \((k=depth-1时)\) 的特殊情况

设最后两个单位分数分母为 \(x, y\) ,则 \(\frac{a}{b}=\frac{1}{x}+\frac{1}{y}\)
整理得

\[\begin{cases} &a\times z=x+y \\ &b\times z=x\times y \end{cases} \]

由韦达定理将 \(x, y\) 转化为一元二次方程 \(x^2-azx+bz\) 的两个不等实根
\(\Delta = a^2z^2-4bz, s=\sqrt{\Delta}\)

\[x=\frac{az-\sqrt{\Delta}}{2},y=\frac{az+\sqrt{\Delta}}{2} \]

枚举 \(z\) ,判断 \(\Delta\) 是否是平方数,再判断 \(az+\sqrt{\Delta}\) 是否是偶数即可

\(z\) 的范围:

\[az=x+y,bz=xy \\ x, y\le S \\ \therefore az \le 2\times S,bz \le S^2 \\ \therefore z \le min(\frac{2S}{a},\frac{S^2}{b}) \]

统计答案:
\(k=depth\) 时,判断 \(a\) 是否等于 \(1\)\(b\) 是否大于 \(last\) ,再比较全局答案数组的 \(ans_k\) 和 当前存的答案数组的 \(tmp_k\) 比较,若当前更小,更新答案

k短路

A*算法

A* 是 dijkstra 的升级版
建反图跑一边最短路,求出每个点的 启发函数 \(h\)
再正着bfs,设从起点到当前点的距离为 \(g\) ,估价函数为 \(f=g+h\)
把节点加入优先队列,每次取出 \(f\) 值最小的节点更新其它点
\(k\) 次经过终点时就是 k短路

Tips:

  • vector可以直接比较字典序的大小

数列分块入门2

题目描述:给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数。

块内排好序,存排完序之后的位置用于单点加
整块的直接加到 tag 上,边角暴力加,然后重新排这一块的序
查询的时候块内 lower_bound 边角暴力查

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=50050;
const int Inf=2e9;

int n;
int len;
pair<int,int> w[N];
int blk[N],pos[N],tag[N];
int lft[N],rgh[N];

int lwrbnd(int l,int r,int x) {
	l--,r++;
	while(r-l>1) {
		int m=l+r>>1;
		if(w[m].first<x) l=m;
		else r=m;
	}
	return l+1;
}

int main() {
	scanf("%d",&n);
	len=sqrt(n);
	for(int i=1;i<=n;i++) blk[i]=(i-1)/len+1,lft[blk[i]]=Inf,rgh[blk[i]]=-Inf;
	for(int i=1;i<=n;i++) lft[blk[i]]=min(lft[blk[i]],i),rgh[blk[i]]=max(rgh[blk[i]],i);
	for(int i=1;i<=n;i++) scanf("%d",&w[i].first),w[i].second=i;
	for(int i=1;i<=(n-1)/len+1;i++) sort(w+lft[i],w+rgh[i]+1);
	for(int i=1;i<=n;i++) pos[w[i].second]=i;
	for(int o=1;o<=n;o++) {
		int opt,l,r,x;
		scanf("%d%d%d%d",&opt,&l,&r,&x);
		if(opt==0) {
			for(int i=l;i<=min(r,rgh[blk[l]]);i++) w[pos[i]].first+=x;
			sort(w+lft[blk[l]],w+rgh[blk[l]]+1);
			for(int i=lft[blk[l]];i<=rgh[blk[l]];i++) pos[w[i].second]=i;
			if(blk[l]!=blk[r]) {
				for(int i=lft[blk[r]];i<=r;i++) w[pos[i]].first+=x;
				sort(w+lft[blk[r]],w+rgh[blk[r]]+1);
				for(int i=lft[blk[r]];i<=rgh[blk[r]];i++) pos[w[i].second]=i;
			}
			for(int i=blk[l]+1;i<blk[r];i++) tag[i]+=x;
		}
		else {
			x=x*x;
			int ans=0;
			for(int i=l;i<=min(r,rgh[blk[l]]);i++) if(w[pos[i]].first<x-tag[blk[l]]) ans++;
			if(blk[l]!=blk[r]) for(int i=lft[blk[r]];i<=r;i++) if(w[pos[i]].first<x-tag[blk[r]]) ans++;
			for(int i=blk[l]+1;i<blk[r];i++) ans+=(lwrbnd(lft[i],rgh[i],x-tag[i])-lft[i]);
			printf("%d\n",ans);
		}
	}
	
	return 0;
} 
posted @ 2024-03-07 19:57  OrangeStar*  阅读(9)  评论(0编辑  收藏  举报