【题解】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 水题。

浙公网安备 33010602011771号