zoukankan      html  css  js  c++  java
  • v·y「状压dp」

    一直对状压dp怀有一种恐惧感

    不会打,不会调,关键是不会调

    做了这两道题,虽然还是不会状压dp,但总比之前好了一些

    y

     普通状压应该很好打

    复杂度$O(2^d*n*(n+m))$

        for(ll i=2;i<=d;i++){
            for(ll state=0;state<=maxn;state++){
                for(ll x=1;x<=n;x++){
                    for(ll j=head[x];j;j=nxt[j]){
                        ll y=ver[j];
                        if(!f[i-1][x][state]) continue ;
                        f[i][y][(state<<1)|edg[j]]|=f[i-1][x][state];
                    }
                }
            }
        }

    那么该怎么优化,

    折半搜索,你起点是确定的,枚举中间点,这样复杂度就降低成$O(2^{frac{d}{2}}*n*(m+n)+2^d*n)$

    最终枚举中间点,

    这样做思想很重要

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 10101010
    bool f1[21][93][1<<12],f2[21][93][1<<12],hash_map[1<<22];
    ll nxt[A],ver[A],head[A],edg[A];
    ll n,m,q,ans,tot,d;
    void add(ll x,ll y,ll z){
        nxt[++tot]=head[x],head[x]=tot,ver[tot]=y,edg[tot]=z;
    }
    void turn(ll x,ll n)
    {
         ll t=x,num=0,xx[100];
         while(x) xx[num++]=x%2,x/=2;    
         for(ll i=num;i<n;i++)printf("0");
         for(ll i=num-1;i>=0;i--)cout<<xx[i];
     //    puts("");
    }
    int main(){
        scanf("%lld%lld%lld",&n,&m,&d);
        for(ll i=1,a,b,c;i<=m;i++){
            scanf("%lld%lld%lld",&a,&b,&c);
            add(a,b,c);add(b,a,c);
        }
        for(ll i=head[1];i;i=nxt[i]){
            ll y=ver[i];
            f1[1][y][edg[i]]=1;
        }
        ll d1=d/2,d2=d-d1;
        ll maxn1=(1<<(d1))-1,maxn2=(1<<(d2))-1;
    //    printf("d1=%lld d2=%lld
    ",d1,d2);
        for(ll i=2;i<=d1;i++){
            for(ll state=0;state<=((1<<i)-1);state++){
                for(ll x=1;x<=n;x++){
                    for(ll j=head[x];j;j=nxt[j]){
                        ll y=ver[j];
                        if(!f1[i-1][x][state]) continue ;
                        f1[i][y][(state<<1)|edg[j]]|=f1[i-1][x][state];
                    }
                }
            }
        }
        for(ll i=1;i<=n;i++){
            for(ll j=head[i];j;j=nxt[j]){
                ll y=ver[j];
                f2[1][y][edg[j]]=1;
            }
        }
    //    printf("f2[1][1][1]=%lld
    ",1ll*f2[1][1][1]);
        for(ll i=2;i<=d2;i++){
            for(ll state=0;state<=((1<<i)-1);state++){
                for(ll x=1;x<=n;x++){
                    for(ll j=head[x];j;j=nxt[j]){
                        ll y=ver[j];
                        if(!f2[i-1][x][state]) continue ;
                        
    //                    printf("f2[%lld][%lld][%lld]=%lld
    ",i-1,x,state,1ll*f2[i-1][x][state]);
                        f2[i][y][(state<<1)|edg[j]]|=f2[i-1][x][state];
    //                    printf("f2now[%lld][%lld][%lld]=1
    ",i,y,(state<<1)|edg[j]);
                    }
                }
            }
        }
        for(ll state=0;state<=maxn1;state++){
            for(ll state1=0;state1<=maxn2;state1++)
                for(ll i=1;i<=n;i++){
    //                printf("f1[%lld][%lld][%lld]=%lld f2[%lld][%lld][%lld]=%lld state1=%lld
    ",d1,i,state,1ll*f1[d1][i][state],d2,i,state1,1ll*f2[d2][i][state1],maxn2);
                    if(f1[d1][i][state]&&f2[d2][i][state1]){
                        ll sum=state<<d2|state1;
    //                    printf("***** i=%lld state=%lld state2=%lld
    ",i,state,state1);
    //                    turn(sum,1);
    //                    printf("
    ");
                        if(!hash_map[sum])
                            hash_map[sum]=1,ans++;
                    }
            }
        }
        printf("%lld
    ",ans);
    }
    View Code

    v

    题解

    记忆化搜索+hash表

    关于题目中说的编号右移,二进制下模拟一下就行了

            st3=(st>>(l-p+1)<<(l-p))|((st&((1<<(l-p))-1)));

    先右移再左移消掉这一位,然后后面保持原样

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll int
    #define mod 19260817
    struct hash_map{
        ll head[mod],nxt[mod],ver[mod];
        ll cnt;
        short len,L[mod];
        double val[mod];
        double &operator [] (const ll & st){
            int x=1ll*st*len%mod;
            for(ll i=head[x];i;i=nxt[i])
                if(ver[i]==st&&L[i]==len)
                    return val[i];
            nxt[++cnt]=head[x],head[x]=cnt,ver[cnt]=st,L[cnt]=len,val[cnt]=-1;
            return val[cnt];
        }
    }f;
    ll n,k;
    char c[33];
    double dfs(ll l,ll st){
        if(l==n-k) return 0;
        f.len=l;
        if(f[st]>-0.5) return f[st];
        ll lst[33];
        ll rst=st;
        f[st]=0;
        for(ll i=1;i<=l;i++) lst[i]=rst&1,rst>>=1;
        for(ll i=1;i<=l/2;i++){
            ll j=l-i+1,st1=(st>>(l-i+1)<<(l-i))|(st&((1<<(l-i))-1)),st2=(st>>(l-j+1)<<(l-j))|(st&((1<<(l-j))-1));
            double ans1=dfs(l-1,st1)+lst[j],ans2=dfs(l-1,st2)+lst[i];
            f.len=l;f[st]+=2.0/((double)l)*max(ans1,ans2);
        }
        if(l&1){
            ll p=l/2+1,st3=(st>>(l-p+1)<<(l-p))|((st&((1<<(l-p))-1)));
            double ans3=dfs(l-1,st3)+lst[p];
            f.len=l;f[st]+=1.0/l*ans3;
        }
        return f[st];
    }
    int main(){
        scanf("%d%d",&n,&k);
        scanf("%s",c+1);
        ll st=0,cnt=0;
        for(ll i=1;i<=n;i++){
            st=((st<<1)|(c[i]=='W'));
            if(c[i]=='W') cnt++;
        }
        if(k==n){
            printf("%d
    ",cnt);
            return 0;
        }
        printf("%.8lf
    ",dfs(n,st));
    }
    View Code
  • 相关阅读:
    免费的asp.net空间
    利用instr()函数防止SQL注入攻击
    Dreamweaver中sql注入式攻击的防范
    编写通用的ASP防SQL注入攻击程序
    跨站式SQL注入技巧
    防范Sql注入式攻击
    PHP与SQL注入攻击
    SQL注入攻击的原理及其防范措施
    SQL注入法攻击一日通
    SQL Server应用程序中的高级SQL注入
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11616258.html
Copyright © 2011-2022 走看看