考试总结 模拟$98$

心态上,这一场似乎并没有完全从上一场的阴影中走出来

看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;
                }
            }
        }
    }
}
原文地址:https://www.cnblogs.com/casun547/p/11787421.html