日记

日记

周五 3月 28 2025
632 字 · 4 分钟

都半期了我怎么还那么菜!!!

Counting Rhyme

我们设 flifl_i 表示 aa 里是否有 ii 的因子,dpidp_i 表示有几组 gcd(ax,ay)=i\gcd(a_x,a_y) = i。显然这两个东西都可以在 O(nlnn)O(n \ln n) 的复杂度内求解,那么最终的复杂度就是 O(nlnn)O(n \ln n)甚至还比 O(nlog2n)O(n \log_2 n) 优。

Non-Intersecting Subpermutations

2024/5/14 做过。好臭的日期

我们设 dpi,jdp_{i,j} 表示在前 ii 个数里,第 (ij,i](i - j,i] 个数内没有重复的情况下的贡献。答案就是 i=1ndpi,k\sum\limits_{i = 1}^{n}dp_{i,k}

我们考虑如何转移。我们想两种情况:第 ii 位是否在 dpi1,j1dp_{i - 1,j - 1} 这不重复的 j1j - 1 个里面。如果不在,那么就会增加 dpi1,j1×(kj+1)dp_{i - 1,j - 1} \times (k - j + 1) 的贡献。如果在,我们考虑枚举这个数在哪里重复了,增加 l=jk1dpi1,l\sum\limits_{l = j}^{k - 1}dp_{i - 1,l} 的贡献。

放一下代码:

#include<bits/extc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
int n,k;
int dp[4005][4005],pw[4005];
signed main()
{
cin >> n >> k;
pw[0] = 1;
for (int i = 1; i <= n; i++)
pw[i] = pw[i - 1] * k % mod;
dp[1][1] = k;
int ans = 0;
for (int i = 2; i <= n; i++)
{
int tmp = 0;
dp[i - 1][0] = dp[i - 1][k];// 我不明白
for (int j = k; j >= 1; j--)
{
if (j != k)
tmp = (tmp + dp[i - 1][j]) % mod;
dp[i][j] = (dp[i - 1][j - 1] * (k - j + 1) + tmp) % mod;
}
ans = (ans + dp[i][k] * pw[n - i]) % mod;
}
cout << ans;
return 0;
}

我不明白:为啥要 dp[i - 1][0] = dp[i - 1][k]

Another MEX Problem

我们看到:异或??!MEX??!考虑不做

这俩恶心扒拉的东西凑一起了,我们不做也得做

看到异或,我们的最优性 dp 直接原地爆炸,考虑可行性 dp。我们发现,50005000 以下数再怎么也异或不出大于 1000010000 的数,更适合可行性 dp 了。设 dpi,jdp_{i,j} 表示前 ii 个数能否异或出 jj。考虑转移:枚举上一段的结尾 kk,那么有 dpi,jdpk,jMEXl=k+1ialdp_{i,j} \leftarrow dp_{k,j \oplus \operatorname{MEX}_{l = k + 1}^{i}a_l}。但是这样有 O(n3)O(n^3) 的复杂度,显然不可行。

考虑优化:我们定义一种东西叫“好的区间”,其意义为:对于区间 [l,r][l,r],不存在区间 [l,r][l',r'] 使得 MEXi=lrai=MEXi=lr\operatorname{MEX}_{i = l}^{r}a_i = \operatorname{MEX}_{i = l'}^{r'}。可以证明这种区间只有 O(n)O(n) 个,然而我并不会。于是我们只用转移这些个好的区间,时间复杂度 O(n2)O(n^2)

后日谈

即使注定失败,你也会坚持下去吗?

反正我会。


Thanks for reading!

日记

周五 3月 28 2025
632 字 · 4 分钟