不会的好题总结

1. 天天爱前缀和

\(n(n\le4000)\) 长的序列 \(a_i(a_i<2^{12})\),你需要选择 \(a_i\)​ 的一个非空子序列,满足子序列中不存在连续四个数异或和为 \(s(s<2^{12})\),求方案数,\(a_i\)​ 互不相同。

题解:

存后三个数的暴力略。

\(f_{x,y}\):从左往右选数,当前选的最后一个数在 \(x\),选的倒数第二个数在 \(y\) 的合法方案数。

\[f_{x,y}=\sum_{z<y} (f_{y,z}-\sum_{i<z,a_x\oplus a_y\oplus a_z\oplus a_i=s}f_{i,z}) \]

这时候我们不得不思考我们拼接是否合法的问题,首先 \(x,y,z,i\) 不合法我们用了一下容斥,但是容斥减去的东西是对的吗?我们减去了 \(x,y,z,i\) 不合法,但是却用了 \(f_{i,z}\)\(f\) 只保证了 \(z\) 前合法,而 \(i,z\) 拼接上 \(y\) 这一步合法吗?我们发现实际上 \(a_x\oplus a_y\oplus a_z\oplus a_i=s\)\(a_i\) 互不相同的已经限制了 \(y\) 前合法,而到 \(x\) 第一次不合法。


现在到了维护时间!这是我喜欢这题的地方,他是很好的前缀和练习题。

总之就是考虑新的 \(f_{x,y}\) 对这三个数组的影响。

\[f_{x,y}=qz_y-t_{y,a_x\oplus a_y\oplus s} \]

\[qz_y=\sum_{z<y}f_{y,z} \]

\[t_{y,m}=\sum_{i<z<y,a_z\oplus a_i=m}f_{i,z} \]

\(qz_x\) 可以直接处理,因为转化为了一维偏序。

容易发现在枚举 \(x\) 的时候处理 \(t_{x,m}\),现在复杂度还是很炸。

trick:增量处理含义有偏序的数组。

\[\begin{aligned} t_{y,m}&=\sum_{i<z<y-1,a_z\oplus a_i=m}f_{i,z}+\sum_{i<z=y-1,a_z\oplus a_i=m}f_{i,z}\\ &=t_{y-1,m}+\sum_{i<y-1,a_{y-1}\oplus a_i=m}f_{i,y-1}\\ &=t_{y-1,m}+d_{y-1,m} \end{aligned} \]

其中

\[d_{p,m}=\sum_{i<p,a_i\oplus a_p=m}f_{i,p} \]

因为枚举 \(i,p,m\) 是冗杂的,且对 \(i,p\) 限制相对 \(m\) 更紧密,然后发现只枚举 \(i<p\) 就可以更新 \(d_{p,m}\) 数组,也转化为了一维偏序。

总结:

此题允许 \(O(n^2)\),所以一维偏序直接做的时间复杂度是对的,所以化到一维就好了。(最底层的是每个形如 \(j<i\)\(\{j,i\}\) 组合只会贡献一次,但是我们每次是用刚出来的 \(f_{x,j}\) 去贡献)

代码:
#include<bits/stdc++.h>
using namespace std;
const int QAQ=4100,mo=998244353;
int n,m,s,a[QAQ],f[QAQ][QAQ],d[QAQ][QAQ],qz[QAQ],t[QAQ][QAQ],ans;
#define jia(x,y) x=((x)+(y))%mo;
signed main()
{
	cin>>n>>m>>s;
	for(int x=1;x<=n;x++)
	{
		cin>>a[x],f[x][0]=1;
		for(int y=0;y<x;y++)
		{
			if(y)
				f[x][y]=(qz[y]-t[y][a[x]^a[y]^s]+mo)%mo,
				jia(d[x][a[y]^a[x]],f[x][y]);
			jia(qz[x],f[x][y]);
		}
		for(int i=0;i<(1<<m);i++) t[x][i]=(t[x-1][i]+d[x-1][i])%mo;
		ans=(ans+qz[x])%mo;
	}
	cout<<ans;
	return 0;
}

2. 天天爱计数

给定 \(n,m,k,n\le 5×10^7\)\(m\) 为字符集大小,问有多少长为 \(n\) 的字符串满足不存在长度为 \(2k\) 的连续子串使得前一半和后一半相同。对 \(998244353\) 取模。

题解:

\(f_i\)\([1,i]\) 合法方案数。
\(f_i=f_{i-1}×m-不合法方案数\)
不合法方案数是 \(f_{i-k}\) 吗?
这个和第一题一样,我们直接使用 \(f_{i-k}\) 是不可以的,因为我们相当于没有告诉 DP 数组 \([i-k+1,i]\) 的情况。
那么我们思考一下什么时候 \([i-k+1,i-1]\) 会使得 \(f_{i-k}\) 本身不合法(当然我们必须在第一次不合法的时候计数,所以我们需要使得 \(f_{i-k}\) 合法,才能构造不合法的字符串)。
推一下性质:
手玩一下临界情况,发现 \([i-k+1,i-1]\) 始终包含 \(i-k\)\(i-2*k\) ,所以我们钦定这两个数不相等即可,同时相等也必然不合法。
所以不合法方案数是 \((m-1)f_{i-k-1}\)
注意前 \(2k\) 预处理。

3.

posted @ 2025-09-21 19:26  _a1a2a3a4a5  阅读(20)  评论(0)    收藏  举报