ZJOI 2019 补题记录

博主分享了ZJOI 2019的补题经历,包括D1T1的和牌判断dp、D1T2的概率数据结构、D1T3的矩阵快速幂优化、D2T1的状态转移和D2T2的路径计数。D2T3中,通过二分和区间加解决直线排名问题,探讨了算法思想和复杂度分析。
摘要由CSDN通过智能技术生成

去年花了大概并不长的时间口胡了四个 (D1T2, D1T3, D2T1, D2T2),感觉比 ZJOI 2018 不知道友好到哪里去了。然后 D1T1 不会算复杂度跑路了,D2T3 只会 \O(nk^2\log(n)) (后面用奇技淫巧优化到了 \O(nk(k+\log(MAXA))\log(k)) 然后卡了。

在 little_waxberry 神仙的指点下意识到 D2T3 只用关心每条直线最上面的一次 occurence(也就是说剥掉上层凸壳之后上面的直线只会起到增加其它直线 rank 的作用而不会被计入答案),顿悟,才发现之前自己一直在试图把凸壳前 k 层的完整形态求出来(其实前 k 层加起来就已经有 \O(nk^2) 段了,标算的复杂度是不可能做到的,这辈子都不可能做到的),然后会了。可能这就是菜吧。

感觉这个 2020 年状态一直不太行……经常浮躁而无法静下来去分析一个问题试图突破……希望,能改改吧。

D1T1

由于某种原因鸽了。

人有多大胆,地有多大产。

考虑怎么判断和牌:dp 即可。dp[i][j][k][l] 表示考虑了值为 [1, i] 的牌,有 j 个 (i-1, i, i+1) 的顺子,k 个 (i, i+1, i+2) 的顺子,l 个对子的方案数,再记一下不同对子个数的最大值。注意只存那些目前还没和的状态,总共只有几百个。

再用一个 dp 套它,dp for dp. 时间复杂度 \O(n [\text{number of states}]).

D1T2

套路数据结构题

令 g(v) 表示节点 v 上有 tag 的概率并维护。遗憾的是这玩意没法转移。

观察为啥没法转移。考虑除了 g(v) 之外再维护 f(v) 表示 v 到根的链上至少有一个 tag 的概率。然后这二者可以相互转移。

用线段树维护。时间复杂度 \O(n \log(n))

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (int)(n); i ++)
#define rep1(i, n) for(int i = 1; i <= (int)(n); i ++)
#define MP make_pair

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MOD = 998244353;
const int INV2 = (MOD + 1) / 2;
int pwi2[100005];

int n, m, sum;
int f[262144], g[262144];
int cnt[262144];

void pushdown(int v)
{
	cnt[v << 1] += cnt[v];
	f[v << 1] = (1 - pwi2[cnt[v]] + 1LL * f[v << 1] * pwi2[cnt[v]] + MOD) % MOD;
	cnt[v << 1 | 1] += cnt[v];
	f[v << 1 | 1] = (1 - pwi2[cnt[v]] + 1LL * f[v << 1 | 1] * pwi2[cnt[v]] + MOD) % MOD;
	cnt[v] = 0;
}
void modify(int rt, int cl, int cr, int l, int r, int ccnt)
{
	if(r < cl || l > cr) {
		sum = (sum - g[rt] + MOD) % MOD;
		g[rt] = 1LL * (g[rt] + f[rt]) * INV2 % MOD;
		sum = (sum + g[rt]) % MOD;
		return;
	}
	
	if(l <= cl && r >= cr) {
		cnt[rt] ++;
		sum = (sum - g[rt] + MOD) % MOD;
		g[rt] = 1LL * (g[rt] + 1) * INV2 % MOD;
		sum = (sum + g[rt]) % MOD;
		f[rt] = 1LL * (f[rt] + 1) * INV2 % MOD;
		return;
	}
	sum = (sum - g[rt] + MOD) % MOD;
	g[rt] = 1LL * g[rt] * INV2 % MOD;
	sum = (sum + g[rt]) % MOD;
	f[rt] = 1LL * f[rt] * INV2 % MOD;
	pushdown(rt);
	int mid = cl + cr >> 1;
	modify(rt << 1, cl, mid, l, r, ccnt);
	modify(rt << 1 | 1, mid + 1, cr, l, r, ccnt);
}

int main()
{
	scanf("%d%d", &n, &m);
	pwi2[0] = 1;
	rep1(i, m) pwi2[i] = 1LL * pwi2[i - 1] * INV2 % MOD; 
	int cur = 1;
	rep(i, m) {
		int t, l, r;
		scanf("%d", &t);
		if(t == 1) {
			scanf("%d%d", &l, &r);
			modify(1, 1, n, l, r, 0);
			cur = 2 * cur % MOD;
		} else {
			l = 1LL * cur * sum % MOD;
			printf("%d\n", l);
		}
	}
	return 0;
}

 

 

D1T3

2 * 2 矩乘的 1e5 n log^2 n,比想象中稳

设最终在根上的值为 val

我们不关心一个节点上的具体值;我们只关心它和 val 的大小关系。

考虑我们对于每个 A \in [l - 1, r]  计算 ans \leq A 的叶子集合数量。

固定 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值