1 条题解
-
0
神秘脑电波还在追我???
题意
给定 ,要求构造长度不超过 、字符集不超过 的字符串使其本质不同子序列个数恰好 。
思路
首先需要意识到,几个特殊性质是用来帮助你骗分不是用来帮助你过题的。
然后需要意识到,这个限制及其宽松。所以我们考虑加强:将字符集缩到 !
这样我们的思路就集中多了。尝试对一个字符串进行计数。
设 表示前 项中以 结尾的子序列个数。对于一个长为 的字符集为 的序列 则有转移:
$$$ dp_{i,a_i}=dp_{i-1,0}+dp_{i-1,1}\\ dp_{i,\neg a_i}=dp_{i-1,\neg a_i} $$$初始 ,最终答案为 。
又假如现在我们已经有了 ,考虑验证其是否是合法的。
我们先不用管 的限制。若要从 推回 的话必然是将大的减去小的,且如果合法的话,减到最后会剩下 ,再进行一次就是 。
这玩意不是辗转相减吗?所以这个等价于 !我们只需找到一组 满足它们互质即可。
这玩意等价于 与 互质,也就是说,如果我们随机一个,合法的概率为 。根据一些神秘计算我们得知这玩意的期望值为 ,于是期望取 次就能找到合法的。
但是我们刚刚没有考虑 的限制!辗转相除的期望次数是 ,但是我们在做辗转相减!
考虑什么情况下会爆炸,也就是当 远大于 时会减一亿次。那我们能做的只有将 的初值设的范围小一点,差不多在 这样。不过不管这个好像也能过就是了。
时间复杂度 。
代码
友情提示:不要用
rand()。#include <bits/stdc++.h> using namespace std; typedef long long ll; ll n, T, len; char ans[1002]; ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } mt19937_64 rnd(random_device{}()); inline ll rd(ll l, ll r) { return rnd() % (r - l + 1) + l; } int main() { cin >> T; while (T -- ) { cin >> n; n ++; while (1) { len = 0; ll dp0 = rd(1, n - 1), dp1 = n - dp0; while (gcd(dp0, dp1) != 1) dp0 = rd(1, n - 1), dp1 = n - dp0; while (len <= 1000 && (dp0 > 1 || dp1 > 1)) { if (dp0 > dp1) dp0 -= dp1, ans[++ len] = 's'; else dp1 -= dp0, ans[++ len] = 'b'; } if (dp0 > 1 || dp1 > 1) continue; for (ll i = 1; i <= len; i ++ ) putchar(ans[i]); putchar('\n'); break; } } }
- 1
信息
- ID
- 6663
- 时间
- 6000ms
- 内存
- 356MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者