zoukankan      html  css  js  c++  java
  • 2734: [HNOI2012]集合选数

    Description

    《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了。
     
    Input

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


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

    4
    Sample Output
    8

    【样例解释】

    有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。

    一开始是这样想的,不能一起选的连一条边然后在图上dp

    1

    2   3

    4   6   9

    8   12 18

    但是好像不行

    看了题解才知道

    我们把图弄成这样(往下走是*2,往右走是*3,就变成相邻的数不能选,可以用状压dp)

    1   3   9

    2   6   18

    4   12 36

    8   24 72

    ............

    但是要注意这个时候我们并没有把所有的数都考虑到,比如5的倍数,所以我们枚举左上角的数,然后用乘法定理

    具体做法是用一个flag存这个数是否考虑过,没考虑就把他当做左上角的数做一遍

     1 const
     2         h=1000000001;
     3         maxn=100010;
     4 var
     5         f:array[0..18,0..2048]of longint;
     6         num:array[0..18]of longint;
     7         flag:array[0..maxn]of boolean;
     8         n:longint;
     9         ans:int64;
    10 
    11 function get(x:longint):int64;
    12 var
    13         i,j,k,s,w:longint;
    14 begin
    15         get:=0;
    16         s:=x;
    17         w:=x;
    18         flag[x]:=true;
    19         num[1]:=1;
    20         while w*3<=n do
    21           begin
    22             w:=w*3;
    23             flag[w]:=true;
    24             inc(num[1]);
    25           end;
    26         for j:=0 to 1<<(num[1])-1 do
    27           if j and(j<<1)=0 then f[1,j]:=1;
    28         i:=1;
    29         while s*2<=n do
    30           begin
    31             inc(i);
    32             s:=s*2;
    33             w:=s;
    34             num[i]:=1;
    35             flag[w]:=true;
    36             while w*3<=n do
    37               begin
    38                 w:=w*3;
    39                 flag[w]:=true;
    40                 inc(num[i]);
    41               end;
    42             for j:=0 to 1<<(num[i])-1 do
    43               f[i,j]:=0;
    44             for j:=0 to 1<<(num[i])-1 do
    45               for k:=0 to 1<<(num[i-1])-1 do
    46                 if (j and(j<<1)=0) and (j and k=0) then f[i,j]:=(f[i,j]+f[i-1,k])mod h;
    47           end;
    48         for j:=0 to 1<<(num[i])-1 do
    49           inc(get,f[i,j]);
    50 end;
    51 
    52 procedure main;
    53 var
    54         i:longint;
    55 begin
    56         read(n);
    57         ans:=1;
    58         for i:=1 to n do
    59           if flag[i]=false then ans:=(ans*get(i))mod h;
    60         writeln(ans);
    61 end;
    62 
    63 begin
    64         main;
    65 end.
    View Code
  • 相关阅读:
    第010讲~第011讲:一个打了激素的数组
    练习15--阅读文件
    第007讲~第009讲:了不起的分支和循环
    第006讲:Python之常用操作符
    第005讲:闲聊之python的数据类型
    练习14--提示和传递
    第004讲:改进我们的小游戏
    ICPC Central Europe Regional Contest 2019 H. Ponk Warshall
    2019 ICPC Asia Yinchuan Regional G. Pot!!(线段树 区间更新 区间查询)
    CF1286A Garland
  • 原文地址:https://www.cnblogs.com/Randolph87/p/3677786.html
Copyright © 2011-2022 走看看