zoukankan      html  css  js  c++  java
  • #12【BZOJ3003】LED BFS+状压DP

    题解:

    看到区间修改先想一下差分

    这题用差分是为了分析问题

    现在的问题就变成了

    原序列全为0,要使得特定的k个点变为1,每个操作改变x,y+1

    然后我们会发现

    对于二元组a,b我们要修改它,实际上是在找连续的区间相连,所以实质上是最短路

    为什么要差分了才能这么做呢

    因为原来的区间修改可能中间涉及了有效点而变得复杂

    现在每次有效操作不会影响到中间的有效点

    接下来状压dp这是显然的

    对于每一个状态,枚举二元组(确定其中一个值,枚举另一个值)

    这是因为被确定的这个值一定是其中一个二元组

    在做这个之前,还需要证明的是三元组,4元组。。。是无效的

    首先奇数是不可能的

    看一下四元组,一定是可以拆分成两个无关的二元组

    非常的智障的是我写最短路的时候只往一边走。。 应该要往两边扩展

    #include <bits/stdc++.h>
    using namespace std;
    int T,n,m,k;
    int len[200],s[200];
    #define rg register
    #define IL inline
    #define N 10100
    #define N2 1100000
    #define INF 1e9
    #define max(a,b) (a)>(b)?(a):(b)
    #define min(a,b) (a)<(b)?(a):(b)
    char ss[1<<17],*A=ss,*B=ss;
    inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?EOF:*A++;}
    template<class T>void read(T&x){
        rg int f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48;
        while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f;
    }
    bool ff[N],f[N];
    queue<int> q;
    int dis[200][N],dp[N2];
    int main()
    {
      freopen("noi.in","r",stdin);
      freopen("noi.out","w",stdout);
      std::ios::sync_with_stdio(false);
      read(T);
      for (rg int TT=1;TT<=T;TT++)
      {
        memset(ff,0,sizeof(ff));
        int kk=0; 
        read(n); read(m); read(k);
        rg int x,y;
        for (rg int i=1;i<=m;i++) 
          read(x),ff[x]^=1,ff[x+1]^=1;
        for (rg int i=1;i<=n+1;i++) 
          if (ff[i]) s[++kk]=i;
        for (rg int i=1;i<=kk;i++)
          for (rg int j=1;j<=n+10;j++)
            dis[i][j]=INF; 
        for (rg int i=1;i<=k;i++) read(len[i]);
        for (rg int i=0;i<N2;i++) dp[i]=INF;
        for (rg int i=1;i<=kk;i++)
        {
          memset(f,1,sizeof(f));
          q.push(s[i]); dis[i][s[i]]=0;
          while (!q.empty())
          {
            rg int x=q.front(); q.pop();
            for (rg int j=1;j<=k;j++)
              if (x-len[j]>0&&f[x-len[j]])
              {
                dis[i][x-len[j]]=dis[i][x]+1;
                f[x-len[j]]=0;
                q.push(x-len[j]);
              }
            for (rg int j=1;j<=k;j++)
              if (x+len[j]<=n+1&&f[x+len[j]])
              {
                dis[i][x+len[j]]=dis[i][x]+1;
                f[x+len[j]]=0;
                q.push(x+len[j]);
              }
          }
        }
      /*  for (int i=1;i<=kk;i++)
        {
          cout<<endl<<endl;
          for (int j=1;j<=n;j++)
            cout<<dis[i][j]<<" ";
        } */
        for (rg int i=1;i<=kk;i++)
          for (rg int j=1;j<i;j++)
          {
            int x=(1<<(i-1))|(1<<(j-1));
            dp[x]=dis[i][s[j]];
          }
        for (rg int i=1;i<=(1<<kk)-1;i++)
        {
          rg int x;
          for (rg int j=0;j<kk;j++) 
            if ((i>>j)&1)
            {
              x=j+1; break;
            }
          for (rg int j=0;j<kk;j++)
            if ((i>>j)&1&&j+1!=x)
            {
              y=(1<<j)|(1<<(x-1));
              dp[i]=min(dp[i],dp[y]+dp[i^y]);
            }
        }
       /* for (rg int i=1;i<=(1<<kk)-1;i++)
          for (rg int j=i;j;j=i&(j-1))
          {
            for 
            dp[i]=min(dp[i],dp[j]+dp[i^j]);
          } */
        dp[(1<<kk)-1]==INF?cout<<-1<<endl:cout<<dp[(1<<kk)-1]<<endl; 
      }
      return 0;
    }
  • 相关阅读:
    在这个互联网泡沫时代,施主你有何焦虑?
    对于公司最近一次技术分享的总结
    Windows系统下Redis的安装
    论语
    系统的简单和复杂是由什么决定的?
    Swift之 ? 和 !
    div模拟table,可实现左右高度同增长(html布局)
    动态添加的无缝轮播
    根据数据库名获取表和字段信息(mysql版)
    博客园更新了?
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8970889.html
Copyright © 2011-2022 走看看