• 【考试总结】20220402


    图案

    先计算哪些前缀和被分成 \(K\) 个相同的字符串

    设某个合法前缀是 \((A)^K\) 那么在 \(i+1\) 开始跟一段 \(A\) 的前缀都是合法的,长度可以使用 \(\rm Z-Function\) 来计算

    区间覆盖 \(1\) 我写了树状数组,没细想有没有更快的做法

    upd:好像可以使用简单的 差分法 将这题做到不带对数复杂度

    Code Display
    const int N=1e6+10;
    char s[N];
    int z[N],n,k;
    ull hs[N],pw[N];
    bool mark[N];
    inline int get(int l,int r){return hs[r]-hs[l-1]*pw[r-l+1];}
    struct Fenwick_Tree{
        int c[N];
        inline void insert(int x,int v){for(;x<=n;x+=x&(-x)) c[x]+=v;}
        inline int query(int x){int res=0;for(;x;x-=x&(-x)) res+=c[x]; return res;}
    }T;
    signed main(){
        freopen("pattern.in","r",stdin); freopen("pattern.out","w",stdout);
        n=read(); k=read();
        scanf("%s",s+1);
        pw[0]=1;
        rep(i,1,n) pw[i]=pw[i-1]*998244353,hs[i]=hs[i-1]*998244353+s[i];
        for(int len=1;len<=n/k;++len){
            bool legal=1;
            for(int d=2;d<=k;++d){
                if(get(1,len)!=get((d-1)*len+1,d*len)){
                    legal=0;
                    break;
                }
            }
            mark[len*k]=legal;
        }
        z[1]=n;
        for(int i=2,l=0,r=0;i<=n;++i){
            if(i<=r) z[i]=min(z[i-l+1],r-i+1);
            while(i+z[i]<=n&&s[z[i]+1]==s[i+z[i]]) ++z[i];
            if(i+z[i]-1>r) l=i,r=i+z[i]-1;
        }
        for(int i=1;i<=n;++i) if(mark[i]){
            int mxl=min(z[i+1],i/k);
            T.insert(i,1); 
            T.insert(i+mxl+1,-1);
        }
        rep(i,1,n) putchar('0'+(bool)T.query(i));
        putchar('\n');
        return 0;
    }
    

    树点购买

    前两问可以使用贪心来解决,也就是每棵子树里面剩余一个点不进行覆盖,找到根链上最小值来加到答案里面

    第三问不能直接计数,考虑一类和贪心本质一样的 \(\rm DP\) 也就是设 \(f_{x},g_{x}\) 表示是/否全部覆盖的最小花费

    转移分别为

    \[\begin{aligned}g_x&\leftarrow \sum f_{son}-\max f_{son}-g_{son}\\f_{x}&\leftarrow \min\left\{\sum f_{son},g_{x}+a_x\right\}\end{aligned} \]

    方案数统计对着上面式子用简单的加法乘法即可

    Code Display
    const int N=1e6+10;
    vector<int> rely[N],G[N];
    int n,typ,a[N];
    bool cho[N];
    int dp[N],node[N],rem[N];
    inline void dfs(int x,int fat){
        int sum=0,Mx=0;
        if(x!=1&&G[x].size()==1){
            node[x]=x;
            rem[x]=a[x];
            return ;
        }
        for(auto t:G[x]) if(t!=fat){
            dfs(t,x);
            dp[x]+=dp[t];
            if(rem[x]!=rem[t]){
                if(rem[x]<rem[t]){
                    cho[node[x]]=1;
                    dp[x]+=rem[x];
                    node[x]=node[t]; rem[x]=rem[t];
                }else{
                    cho[node[t]]=1;
                    dp[x]+=rem[t];
                }
            }else{
                cho[node[x]]=cho[node[t]]=1;
                dp[x]+=rem[t];            
            }
        }
        if(rem[x]==a[x]) rely[x].emplace_back(node[x]),node[x]=x;
        else if(rem[x]>a[x]) rem[x]=a[x],node[x]=x;
        return ;
    }
    signed main(){
        freopen("purtree.in","r",stdin); freopen("purtree.out","w",stdout);
        n=read();
        rep(i,1,n) a[i]=read();
        for(int i=1;i<n;++i){
            int u=read(),v=read();
            G[u].emplace_back(v);
            G[v].emplace_back(u);
        }
        typ=read();
        int Mn;
        if(typ>=1){
            dfs(1,0);
            print(Mn=dp[1]+rem[1]);
            putchar('\n');
        }
        if(typ>=2){
            cho[node[1]]=1;
            queue<int> q;
            rep(i,1,n) if(cho[i]) q.push(i);
            while(q.size()){
                int fr=q.front(); q.pop();   
                for(auto t:rely[fr]) if(!cho[t]){
                    cho[t]=1; 
                    q.push(t);
                }
            }
            rep(i,1,n) if(cho[i]) print(i); 
            putchar('\n');
        }
        if(typ>=3){
            vector<int> f(n+1),g(n+1);
            vector<int> mf(n+1),mg(n+1);
            function<void(int,int)>DFS=[&](const int x,const int fat){
                if(x!=1&&G[x].size()==1){
                    f[x]=a[x];
                    mf[x]=mg[x]=1;
                    return ;
                }
                vector<int> son;
                int Mx=-1e18;
                int Multf=1,sigf=0;
                for(auto t:G[x]) if(t!=fat){
                    DFS(t,x);
                    if(Mx<f[t]-g[t]){
                        Mx=f[t]-g[t];
                        son={t};
                    }else if(Mx==f[t]-g[t]){
                        son.emplace_back(t);
                    }
                    ckmul(Multf,mf[t]);
                    sigf+=f[t];
                }
                g[x]=sigf-Mx;
                for(auto t:son) ckadd(mg[x],mul(mul(mg[t],ksm(mf[t],mod-2)),Multf));
                if(sigf==g[x]+a[x]){
                    mf[x]=add(mg[x],Multf);
                    f[x]=g[x]+a[x];
                }else if(sigf<g[x]+a[x]){
                    mf[x]=Multf;
                    f[x]=sigf;
                }else{
                    mf[x]=mg[x];
                    f[x]=g[x]+a[x];
                }
                return ;
            };
            DFS(1,0);
            print(mf[1]);
            putchar('\n');
        }
        return 0;
    }
    

    舰队游戏

    \(f_{i,j}\) 表示 \(i\) 点还有 \(j\)\(\rm HP\) 想要走到终点的期望步数

    转移分成走到后继节点和返回 \(1\) 号点补血两种:

    \[f_{i,j}=\min\left\{\frac{1}{deg_i}f_{v,j-d_v},f_{1,H}+H-j\right\} \]

    此时所有的目光都落到了 \(f_{1,H}\) 上面,那么可以发现所有的 \(f_{i,j}\) 可以表达成 \(kf_{1,H}+b\) 的形式

    尝试给 \(f_{1,H}\) 假定权值 \(x\) 并拓扑排序得到 \(f_{1,H}\) 和自己的表达关系,显然要满足 \(k=1,b=0\)

    根据实际含义可以发现如果 \(f_{1,H}\) 小于实际值时会趋向于选择第二个决策,而大于实际值时趋向于第二个决策,所以二分答案找到最后一个满足斜率为 \(1\) 的地方即可

    Code Display
    const int N=110;
    vector<int> G[N];
    int n,m,d[N],H;
    pair<double,double> dp[N][N];
    inline double calc(double V){
        for(int i=n-1;i>=1;--i){
            int Mx=0;
            for(auto t:G[i]) ckmax(Mx,d[t]);
            rep(j,1,H){
                dp[i][j]={0,0};
                if(j<=Mx||!G[i].size()) dp[i][j]={V+1.0*H-j,1.0};
                else{
                    for(auto t:G[i]){
                        dp[i][j].fir+=dp[t][j-d[t]].fir;        
                        dp[i][j].sec+=dp[t][j-d[t]].sec;
                    }
                    dp[i][j].fir/=1.0*G[i].size();
                    dp[i][j].sec/=1.0*G[i].size();
                    dp[i][j].fir++;
                    if(dp[i][j].fir>V+H-j){
                        dp[i][j].sec=1;
                        dp[i][j].fir=V+H-j;
                    }
                }
            }
        }
        return dp[1][H].sec;
    }
    signed main(){
        freopen("kancolle.in","r",stdin); freopen("kancolle.out","w",stdout);
        n=read(); m=read(); H=read();
        for(int i=1;i<=m;++i){
            int u=read(),v=read();
            G[u].emplace_back(v);
        }
        rep(i,1,n) d[i]=read();
        double l=0,r=1e6,ans=r+1;
        if(calc(ans)==1) puts("-1"),exit(0);
        while(r-l>1e-9){
            double mid=(l+r)/2;
            if(calc(mid)<1) r=mid;
            else l=mid,ans=mid;
        }
        printf("%.10lf\n",ans);
        return 0;
    }
    

  • 相关阅读:
    读书笔记_数学之美
    在VMware上安装ubuntu——网络类型
    读书笔记_探索式测试_全局探索式测试法
    读书笔记_探索式测试_软件质量和手工测试
    关系型数据库的范式
    求最小支配集,最小点覆盖,最大独立集
    10.20testT3
    10.24testT3
    [HNOI2015]亚瑟王
    卡塔兰数
  • 原文地址:https://www.cnblogs.com/yspm/p/16092410.html
Copyright © 2020-2023  润新知