[题解] P10950 太鼓达人
P10950 太鼓达人
本题有搜索+判重+剪枝的做法,除了复杂度很玄学之外都比较简单,这里提供一种欧拉路解法。
首先,由一个子串转移到下一个子串,只需要在末尾加一位,然后把最高位删掉即可。
于是考虑图论建模,点用二进制表示每个长度为 \(k\) 的子串,边表示子串间的转移关系。
我们想让 \(m\) 最大,就必须经过所有点,点数是 \(2^k\),因此第一问的答案就是 \(2^k\)。
然而,再往下做,我们发现这是个哈密顿回路,标准NP-Complete问题,那就相当于上面的所有过程全白费了,我们还是得爆搜。
只能转换思路。我们不妨把每个点上的数去掉最后一位,变成 \(k-1\) 位,然后把去掉的最后一位放到边上,这样,每一个子串都可以表示成“点+出边”的形式。现在我们只需要走完所有的边即可。
如下图:

这就成了欧拉路了,不难发现欧拉路一定存在,于是直接跑板子,输出欧拉路的边上的数,结束。
真的结束了吗?
好像并没有,题目要求我们的构造方案要字典序最小,这涉及到起点的选择,如果从一个错误的起点开始跑,就会找到正确答案的循环同构串,不满足要求。
最简单粗暴的方法,就是随便跑出一个序列,然后按P13270 【模板】最小表示法的方法跑出最小表示串输出,但这样太麻烦了,不好用。
首先这个图一定有欧拉路,并且一定得是欧拉回路,那么我们从起点走一个圈又回到起点,不难发现起点状态会出现在最终输出串的末尾 \(k-1\) 位。
为了让字典序最小,我们得把1更多的放到后面,也就是拿1最多的当起点。
于是这个题真的结束了......吗?
还没有。注意位运算操作的优先级问题。
#include<bits/stdc++.h>
using namespace std;
int del[(1<<12)];
int st[(1<<12)], buf[20];
int k,ans,tot;
void Dfs(int u){
for(int i=del[u]; i<=1; i=del[u]){
del[u]++;
int v=((u<<1)|i) & ~(1<<(k-1));
Dfs(v);
st[++tot]=i;
}
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
cin>>k;
cout<<(1<<k)<<" ";
Dfs((1<<(k-1))-1);
while(tot>0){
cout<<st[tot];
tot--;
}
return 0;
}
这次真的结束了

浙公网安备 33010602011771号