• A guess 解题报告


    A guess

    题意

    选一个([1,n](nle 500))的整数,可以询问数是否属于区间([l,r]),多次询问一起回答,统计有多少种询问区间集合(无序)满足可以猜出这个数,对(p(2^{29}le p<2^{30}))取模


    中文题解看不懂,看了一下午英文题解,还是感觉理解的不好,就按照现在的理解说一下吧(为啥这题是今天最简单的啊...

    首先你写暴力的话有个结论

    每个权值(i)都有过询问区间集合(S_i)(S_i)代表覆盖整个值的询问集合。如果有某两个值的询问集合是一样的,那么就猜不出来,否则一定可以猜出来。

    考虑按照这个把每个权值编号(a_i),以最小表示法来编号,要求是若(S_i=S_j),那么有(a_i=a_j)

    不必在乎这个怎么编号的,反正一定可以编出来,可以发现({S})({a})是一个单射,于是我们转过去统计({a})的数量。

    按照要求我们可以统计存在(a_i=a_j)的集合的数量,就是补集的数量。

    如果对于一个集合,有一个(a_i=a_j),那么我们可以把([i,j])区间内的给拿开统计,等价于把这个区间缩成一个点,点的权值为(a_i),把所有类似这样的区间都拿开的话,剩下的集合是没有重复元素的,也就是我们最终需要求得的答案,记为(f_i)

    注意理解一下为什么缩掉区间构成的子问题是相同的。

    然后我们需要得到把一个原来长度为(L)的问题缩到(K)的方案数,设为(g_{L,K})

    不妨先把有关(f)的转移写出来

    [f_i=2^{inom{i+1}{2}}-sum_{j=1}^{i-1}f_jg_{i,j} ]

    即全集减去所有可以缩掉的方案(可缩的话一定不合法)

    然后再考虑如何计算(g)

    按照一些常见组合意义的东西的递推的方法,我们应该枚举最后一个一个集合大小。

    首先不产生一个新的可缩的即(g_{i-1,j-1})(g_{i,j})的贡献

    然后枚举产生的缩掉的区间的大小(k),在这个区间里的询问集合是随意的,即为全集

    那么转移就为

    [g_{i,j}=g_{i-1,j-1}+sum_{k=0}g_{i-k-2,j-1}2^{inom{k+1}{2}} ]

    嗯,感觉还是没理解到本质的东西...

    如果非要写一些思路的话

    把拥有集合的性质通过编号转换到元素统计上去,这点和后缀自动机状态的构建好像有些相似,后缀自动机定义了每个子串的endpos集合,然后按照每个子串集合划分状态,进行统计。这种方法应该可以成为一种思路吧,这个题大概就是通过最小表示法编号。

    然后我们统计数量时,真正涉及计算的时候要回到集合的意义上才能统计,比如这个题就是回到了区间内的集合是全集,才能统计的数量,也只有在这个地方可以简单的进行统计和计算了。


    Code:

    #include <cstdio>
    const int N=510;
    int n,mod,po[N*N],g[N][N],f[N],d[N];
    inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    #define mul(a,b) (1ll*a*b%mod)
    int main()
    {
        scanf("%d%d",&n,&mod);
        po[0]=1;for(int i=1;i<=n*n;i++) po[i]=mul(po[i-1],2);
        for(int i=1;i<=n;i++) d[i]=i*(i+1)/2;
        g[0][0]=1;
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=i;j++)
            {
                g[i][j]=g[i-1][j-1];
                for(register int k=0;k<=i-2;k++)
                    g[i][j]=add(g[i][j],mul(g[i-k-2][j-1],po[d[k]]));
            }
        for(register int i=1;i<=n;i++)
        {
            f[i]=po[d[i]];
            for(register int j=1;j<i;j++)
                f[i]=add(f[i],mod-mul(f[j],g[i][j]));
        }
        printf("%d
    ",f[n]);
        return 0;
    }
    
    

    2019.1.8

  • 相关阅读:
    最近这段时间我,想在2008 的基础上,写2011 有的工具 不知道会样,这次又机会研究ploy
    Screen 可以查找屏幕pos系类的函数
    笔记1
    Ubuntu下如何安装 tar.bz2 文件
    安装ubuntu遇到“BusyBox”问题
    android luancher 如何添加快捷方式
    转 Android 源代码结构
    修改apk图标
    Linux Ubuntu 下如何安装 .SH文件
    解放你的电源键!!不用刷机不用装软件!超简单修改搜索锁屏、HOME键唤醒~~~~~
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10241220.html
Copyright © 2020-2023  润新知