心态上,这一场似乎并没有完全从上一场的阴影中走出来
看T1比较慌,尤其是收到旁边两位大佬的虚假影响,以为T1很水,但是最终也没有看出来怎么做,先搁了
T2第一眼看上去比较像状压,感觉并不稳,所以放在了后面
于是就先写了T3比较好写的暴力,
最后T1暴力没写完
整场只有开始写T2状压的时候才感觉比较稳,真正进入了状态
总的来说思考量一般,T2想到30分之后就没有接着想了
T2「状压DP」
定义s 0/1表示这一位的 关/开 的状态
那么每一次林先森的操作会将其t时间内的父亲节点的状态取反。要是传到根1就不传了
首先发现一个性质:抵消的情况不用管。
为什么?你会发现当你不管抵消的情况,让两次传递分别操作,最后结果是相同的
然后我们会先去想正着推,因为最终答案是不用保证稳定的,所以对于某一次操作的贡献时间并不确定
而倒着想就没有这个问题了,
我们定义f[t][s]表示在倒数第t秒,当前状态是s,是否存在
f[0][ed]=1,我们要到第一个s==0的存在状态,然后输出时间即可
先预处理出对每个点进行操作后,t时间内的贡献
转移就很好写了
//decoration #include<bits/stdc++.h> using namespace std; int fa[20],f[50][1<<17]; int st[20][50]; int n,ed,mx; int main(){ freopen("decoration.in","r",stdin); freopen("decoration.out","w",stdout); scanf("%d",&n); for(int i=2;i<=n;++i) scanf("%d",&fa[i]); for(int i=1;i<=n;++i){ int x;scanf("%d",&x); ed|=x<<(i-1); } for(int x=1;x<=n;++x){ st[x][1]=1<<(x-1); int tmp=fa[x]; for(int t=2;t<=2*n;++t){ st[x][t]=st[x][t-1]; if(tmp)st[x][t]|=(1<<(tmp-1)); tmp=fa[tmp]; } } mx=(1<<n)-1; f[0][ed]=1; for(int t=1;t<=2*n;++t){ for(int s=0;s<=mx;++s){ if(!f[t-1][s])continue; for(int i=0;i<=n;++i){ int ns=s^st[i][t]; f[t][ns]=1; if(!ns){ printf("%d ",t); return 0; } } } } }