zoukankan      html  css  js  c++  java
  • LOJ#3302. 「联合省选 2020 A | B」信号传递 状压DP+卡常

    对于 $x,y$ 如果 $x$ 在 $y$ 的左面那么 $x ightarrow y$ 的贡献是 $pos[y]-pos[x]$  

    $y ightarrow x$ 的贡献是 $pos[x] imes k+pos[y] imes k.$  

    令 $f[S]$ 表示集合 $S$ 在序列开头,且考虑所有贡献的情况下的最小值.   

    那么转移 $f[S]$ 是十分简单的,但是我们需要用到一个 $trans[x][S]$ 数组,这个数组空间开不下.   

    可以考虑枚举 $i$ 与 $(i-1)$ 的差别,然后相同位不改,只改不同位,理论上只需要修改 $2^m$ 次.   

    那么这部分复杂度就是 $O(m 2^m)$ 的,总复杂度也是 $O(m 2^m)$ 的.  

    code:  

    #include <ctime> 
    #include <cstdio>   
    #include <cstring> 
    #include <algorithm>    
    #define N 100008 
    #define ll long long 
    #define lowbit(x) ((x)&(-(x))) 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;      
    int n,m,k,T;       
    int f[1<<23];   
    int a[N],lg[1<<23],bi[24]; 
    int h[24],g[24],m1[24][24],m2[24][24],cnt[1<<23];    
    inline void calh(int i) { 
        int pre,x;    
        pre=i-1-(i&(i-1));          
        while(pre) {   
            x=lg[lowbit(pre)]; 
            for(int j=1;j<=m;++j) { 
                h[j]-=m1[j][x];   
            }  
            pre-=lowbit(pre); 
        }   
        pre=i-(i&(i-1)); 
        while(pre) {   
            x=lg[lowbit(pre)]; 
            for(int j=1;j<=m;++j) { 
                h[j]+=m1[j][x];   
            }  
            pre-=lowbit(pre); 
        }   
    }
    inline void calg(int i) { 
        int pre,x;     
        pre=(i+1)-(i&(i+1));                           
        while(pre) {  
            x=lg[lowbit(pre)];         
            for(int j=1;j<=m;++j) { 
                h[j]-=m2[j][x];      
            }  
            pre-=lowbit(pre); 
        }   
        pre=i-(i&(i+1)); 
        while(pre) {      
            x=lg[lowbit(pre)]; 
            for(int j=1;j<=m;++j) { 
                h[j]+=m2[j][x];   
            }  
            pre-=lowbit(pre); 
        }   
    }
    int main() { 
        // setIO("input");    
        scanf("%d%d%d",&n,&m,&k);   
        for(int i=1;i<=n;++i) { 
            scanf("%d",&a[i]); 
        }   
        for(int i=1;i<n;++i) {  
            if(a[i]==a[i+1]) { 
                continue;  
            }
            m1[a[i]][a[i+1]]+=k;
            m1[a[i+1]][a[i]]+=1;                 
            --m2[a[i]][a[i+1]]; 
            m2[a[i+1]][a[i]]+=k;  
        }   
        for(int i=1;i<=m;++i) { 
            bi[i]=1<<(i-1);    
            lg[bi[i]]=i;     
        }                        
        memset(f,0x3f,sizeof(f)); 
        f[0]=0;     
        T=(1<<m)-1;   
        for(int i=1;i<=m;++i) {  
            for(int j=1;j<=m;++j) { 
                h[i]+=m2[i][j];  
            }
        }  
        int x,y,z; 
        for(int i=1;i<(1<<m);++i) {  
            calh(i);  
            calg(T-i);     
            cnt[i]=cnt[i-lowbit(i)]+1;  
            int cur=i;  
            while(cur) { 
                x=lg[lowbit(cur)];  
                f[i]=min(f[i],f[i-bi[x]]+cnt[i]*h[x]); 
                cur-=lowbit(cur); 
            }     
        }  
        printf("%d
    ",(ll)f[T]);  
        return 0; 
    }
    

      

  • 相关阅读:
    POJ 3672 水题......
    POJ 3279 枚举?
    STL
    241. Different Ways to Add Parentheses
    282. Expression Add Operators
    169. Majority Element
    Weekly Contest 121
    927. Three Equal Parts
    910. Smallest Range II
    921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/guangheli/p/13367329.html
Copyright © 2011-2022 走看看