【题解】HDU多校2

Link

今天打的一坨。(;´д`)ゞ

1001 筛子

【unkown】
什tm分圆多项式,不会,交个打的表。
upd:Cat's discovery

1002 数上的图

【分讨,*】
略。

1003 图上的数

【期望,**】
在空序列中均匀随机插入 \(k\) 个数,最终每个数在每个位置的概率均为 \(\frac{1}{k}\)
得到期望为 \(\frac{\sum{p_i} (2^{k}-1)}{k}\)。朴素地,求出每个长度的最长链取最优。
观察式子, \(k\) 值得影响明显。考虑极端情况,我们需要 \(\frac{\frac{1}{10000} (2^{c1}-1)}{c1} > \frac{c2 (2^{c2}-1)}{c2}\),发现 \(c1 - c2 \ge 30\) 时一定成立。拓补排序,维护非零最长,最长等。直接维护即可。

1004

1005

1006 半

【偏序,*】
略。

1007 计数

【DP,多项式,**】
\(a\) 做后缀最大值后得到递推式 \(F[i][x] = \sum_{y=a_{i+1}}^x F[i+1][y]\),这是一个前缀和形式。那 \(F_i(x)\) 就是一个 \(n-i\) 次多项式,二项式系数基上去化简。(多项式不咋会啊)。

1008 井

【期望,*】
略。

1009 苹果树

【树剖,**】
鸟的做法:对度数分治;
std:暴力做不行,但是反过来,在询问的时候观察贡献的来源,如果修改时只修改 \(\operatorname{Fa}\) 和重儿子,那只有链顶需要单独单点查询,\(O(n \log^2n)\)

1010

1011 10010

【线段树,树状数组倍增+Hash,***】
从右到左,最远能找出多少个 1,使得相邻 1 之间的间隔,构成一个公差为1 的等差数列。
方法1:线段树维护信息:左右0的个数,最左gap大小,最右gap大小,是否完成等差,1 的个数。

点我展开看代码
const int N = 1e6 + 10;
int n,m,a[N];
struct node{
	int len, l0, r0;
	int cnt1;
	int over, st, ed;
	node(){}
	node(int x){
		len = 1, l0 = r0 = x == 0;
		cnt1 = x == 1;
		over = 0, st = ed = -1;
	}
	inline int ans(){
		if(!cnt1)return 0;
		if(cnt1 == 1)return r0;
		if(ed == r0 + 1)return st + 2 * (st - ed + 1);
		else return r0;
	}
};
inline node operator +(const node &a, const node &b){
	node res;
	res.len = a.len + b.len;
	res.l0 = a.l0 == a.len ? a.len + b.l0 : a.l0;
	res.r0 = b.r0 == b.len ? b.len + a.r0 : b.r0;
	res.cnt1 = a.cnt1 + b.cnt1;
	if(res.cnt1 < 2){ res.over = 0, res.st = res.ed = -1; return res; }
	if(b.cnt1 == 0){ res.over = a.over, res.st = a.st, res.ed = a.ed; return res; }
	if(a.cnt1 == 0){ res.over = b.over, res.st = b.st, res.ed = b.ed; return res; }
	if(b.over){ res.over = 1, res.st = b.st, res.ed = b.ed; return res; }
	int mid = a.r0 + b.l0;
	if(a.cnt1 == 1 && b.cnt1 == 1){ res.over = 0, res.st = res.ed = mid; return res; }
	if(a.cnt1 == 1){
		if(mid == b.st + 1)res.over = 0, res.st = mid, res.ed = b.ed;
		else res.over = 1, res.st = b.st, res.ed = b.ed;
		return res;
	}
	if(b.cnt1 == 1){
		if(a.ed == mid+1)res.over = a.over, res.st = a.st, res.ed = mid;
		else res.over = 1, res.st = res.ed = mid;
		return res;
	}
	if(a.ed == mid+1 && mid == b.st+1)res.over = a.over, res.st = a.st, res.ed = b.ed;
	else if(mid == b.st + 1)res.over = 1, res.st = mid, res.ed = b.ed;
	else res.over = 1, res.st = b.st, res.ed = b.ed;
	return res;
}
struct Seg{
	node tr[N << 2];
	#define ls (p << 1)
	#define rs (p << 1 | 1)
	#define mid ((l + r) >> 1)
	void build(int p,int l,int r){
		if(l == r)return tr[p] = node(a[l]),void();
		build(ls, l, mid), build(rs, mid+1, r);
		tr[p] = tr[ls] + tr[rs];
	}
	void modify(int p,int l,int r,int x,int v){
		if(l == r)return tr[p] = node(v), void();
		x <= mid ? modify(ls, l, mid, x, v) : modify(rs, mid+1, r, x, v);
		tr[p] = tr[ls] + tr[rs];
	}
	node query(int p,int l,int r,int L,int R){
		if(L <= l && r <= R)return tr[p];
		if(R <= mid)return query(ls, l, mid, L, R);
		if(mid < L)return query(rs, mid+1, r, L, R);
		return query(ls, l, mid, L, R) + query(rs, mid+1, r, L, R);
	}
}seg;
char s[N];
void solve(){
	read(n, m); scanf("%s",s+1);
	rep(i, 1, n)a[i] = s[i]^48;
	seg.build(1, 1, n);
	while(m--){
		int op, x, y; read(op, x);
		if(op == 1)read(y), printf("%d\n",seg.query(1, 1, n, x, y).ans());
		else seg.modify(1, 1, n, x, a[x] ^= 1);
	}
}
int main(){
	int T; read(T);
	while(T--)solve();
	return 0;
}

方法二:树状数组+Hash 先放着。

1012 子集

【线性基,**】
鸟 折半+trie 交了40多发WA和MLE,mmm。我写了线性基,但是没有注意到重要的贪心:线性基本质是从数据集中得到最优答案,那么只需要使得丢进去的数合法且尽量丢即可。即,两个数之间空格最多为 2。计算空间后,剩下 dfs 水题。

posted @ 2025-07-22 19:48  Luzexxi  阅读(189)  评论(0)    收藏  举报