zoukankan      html  css  js  c++  java
  • NC17193 简单瞎搞题

    状态表示:\(f[i][j]\)表示前\(i\)个数是否能组成数\(j\)
    状态转移:枚举\(x_i\)\([l_i,r_i]\)
    时间复杂度最坏为:\(10^{10}\),显然不能接受
    空间复杂度为:\(100 M\),可采用滚动数组优化

    下面针对时间复杂度优化:

    \(f[i][j]\) 为前\(i\)个数字能否构成j,考虑第\(i\)个数选还是不选。

    显然如果\(f[i-1][j-x[i]^2]==1\)的话\(f[i][j]\)就是可以的,\(x[i]\)的取值是\(l[i]\)\(r[i]\)

    这样的话其实是有点浪费的——f数组是一个只有01两个值的数组,哪怕表示成bool类型都有点多余。于是我们可以考虑用bitset来优化它。

    bitset你可以理解为一个长度很长的01数字串(实际上它是用int拼接而成),也可也理解为可以用位运算的bool数组。

    这样的话一行就可以一起求——如果我们用\(f[i]\)来表示第i行的01串那么:\(f[i]=f[i] | (f[i-1]<<(x[j]^2))\)

    然后bitset自带一个求1的个数的函数count,这就非常美滋滋了。

    特别说明:bitset内部实现是用int拼接而成所以时间复杂度是\(O(长度/32)\)的,那么本题的时间复杂度是\(O(n^5/32)\)(bitset最大长度也就是背包体积是\(n^3\),还要枚举n,枚举从\(l_i\)\(r_i\))

    const int N=110,M=1e6+10;
    int l[N],r[N];
    bitset<M> f[N];
    int n;
     
    int main()
    {
        cin>>n;
     
        for(int i=1;i<=n;i++) cin>>l[i]>>r[i];
     
        f[0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=l[i];j<=r[i];j++)
                f[i] |= f[i-1]<<(j*j);
     
        cout<<f[n].count()<<endl;
     
        //system("pause");
    }
    

    滚动数组优化:注意每轮清空

    const int N=110,M=1e6+10;
    int l[N],r[N];
    bitset<M> f[2];
    int n;
     
    int main()
    {
        cin>>n;
     
        for(int i=1;i<=n;i++) cin>>l[i]>>r[i];
     
        f[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            f[i&1].reset();
            for(int j=l[i];j<=r[i];j++)
                f[i&1] |= f[i-1&1]<<(j*j);
        }
     
     
        cout<<f[n&1].count()<<endl;
     
        //system("pause");
    }
    
  • 相关阅读:
    TreeView使用集锦
    net 下安装、调试的常见问题与错误及解决方法 [转]
    Oracle中使用同义词
    再推荐两个blog和一首好歌
    一点感慨
    推荐一个blog和一个工具
    买书了
    第一次做饭
    ORA00911错误及解决方法
    C#3.0美文收集
  • 原文地址:https://www.cnblogs.com/fxh0707/p/13758691.html
Copyright © 2011-2022 走看看