• [HNOI2012]集合选数


    题目描述

    《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。

    同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n<=100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了。

    输入输出格式

    输入格式:

    只有一行,其中有一个正整数 n,30%的数据满足 n<=20。

    输出格式:

    仅包含一个正整数,表示{1, 2,..., n}有多少个满足上述约束条件 的子集。

    输入输出样例

    输入样例#1: 复制
    输出样例#1: 复制
    每个k(不含2,3的因数)可以单独考虑,答案是所有k方案的积
    即考虑$k*2^i*3^j<=n$的方案
    构造一个矩阵:
     k   3k  9k  27k
    2k  6k  18k  54k
    4k 12k  36k 108k
    令f[i][S]表示当前选到2^i,行状态为S
    S第j位为1表示选了2^i*3^j
    首先根据题意,S相邻2位不能为1
    然后转移时前面的状态S'
    要满足与S&S'=0
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 int n,Log2[100001],Log3[100001],pw2[21],pw3[21];
     8 int ans,Mod=1e9+1,f[21][100001],s[100001],cnt,p,q,sum;
     9 int main()
    10 {int i,j,k,l;
    11   cin>>n;
    12   Log2[1]=0;
    13   for (i=2;i<=n;i++)
    14     Log2[i]=Log2[i/2]+1;
    15   Log3[1]=0;
    16   for (i=3;i<=n;i++)
    17     Log3[i]=Log3[i/3]+1;
    18   pw2[0]=1;
    19   for (i=1;i<=18;i++)
    20     pw2[i]=pw2[i-1]*2;
    21   pw3[0]=1;
    22   for (i=1;i<=13;i++)
    23     pw3[i]=pw3[i-1]*3;
    24   for (i=0;i<pw2[13];i++)
    25     {
    26       s[i]=1;
    27       for (j=0;j<=11;j++)
    28     if ((i&pw2[j])&&(i&pw2[j+1])) s[i]=0;
    29     }
    30   ans=1;
    31   for (i=1;i<=n;i++)
    32     if (i%2&&i%3)
    33     {
    34       k=1;
    35       q=Log3[n/i]+1;
    36       for (j=0;j<pw2[q];j++)
    37     f[0][j]=s[j];
    38       while (i*pw2[k]<=n)
    39     {
    40       p=Log3[n/(i*pw2[k])]+1;
    41       for (j=0;j<pw2[p];j++)
    42         if (s[j])
    43         {
    44           f[k][j]=0;
    45           for (l=0;l<pw2[q];l++)
    46         if (s[l]&&((j&l)==0))
    47           {
    48             f[k][j]=(f[k][j]+f[k-1][l])%Mod;
    49           }
    50         }
    51         else f[k][j]=0;
    52       q=p;
    53       k++;
    54     }
    55       sum=0;
    56       for (j=0;j<pw2[q];j++)
    57     sum=(sum+f[k-1][j])%Mod;
    58       ans=(1ll*ans*sum)%Mod;
    59     }
    60   cout<<ans;
    61 }
  • 相关阅读:
    C++迭代器
    JdbcTemplateUtil 工具类分享
    PE和CDlinux二合一启动盘制作
    程序员自述——2019新年篇
    HTML/CSS常用单词
    JAVA学习常用单词
    Spring集成Mybatis3
    Spring集成struts2
    解决VS2010打开Web页面时经常由于内存较低而导致VS2010自动关闭的问题
    年终总结
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8531927.html
Copyright © 2020-2023  润新知