博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2734: [HNOI2012]集合选数 - BZOJ
阅读量:4316 次
发布时间:2019-06-06

本文共 2246 字,大约阅读时间需要 7 分钟。

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 var13         i,j,k,s,w:longint;14 begin15         get:=0;16         s:=x;17         w:=x;18         flag[x]:=true;19         num[1]:=1;20         while w*3<=n do21           begin22             w:=w*3;23             flag[w]:=true;24             inc(num[1]);25           end;26         for j:=0 to 1<<(num[1])-1 do27           if j and(j<<1)=0 then f[1,j]:=1;28         i:=1;29         while s*2<=n do30           begin31             inc(i);32             s:=s*2;33             w:=s;34             num[i]:=1;35             flag[w]:=true;36             while w*3<=n do37               begin38                 w:=w*3;39                 flag[w]:=true;40                 inc(num[i]);41               end;42             for j:=0 to 1<<(num[i])-1 do43               f[i,j]:=0;44             for j:=0 to 1<<(num[i])-1 do45               for k:=0 to 1<<(num[i-1])-1 do46                 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 do49           inc(get,f[i,j]);50 end;51 52 procedure main;53 var54         i:longint;55 begin56         read(n);57         ans:=1;58         for i:=1 to n do59           if flag[i]=false then ans:=(ans*get(i))mod h;60         writeln(ans);61 end;62 63 begin64         main;65 end.
View Code

 

转载于:https://www.cnblogs.com/Randolph87/p/3677786.html

你可能感兴趣的文章
Css 后代选择器与子代选择器的区别
查看>>
广播技术
查看>>
shell-运算符
查看>>
js 问题集锦 之 二
查看>>
MySQL-优化之 index merge(索引合并)
查看>>
20190509 感叹
查看>>
Jlink v8仿真器在64位系统上刷固件
查看>>
入门训练 Fibonacci数列
查看>>
20189222 《网络攻防技术》第一周作业
查看>>
第十二周编程总结
查看>>
数据结构——树——二叉查找树
查看>>
StringBuilder動態串
查看>>
系列文章(二):从WLAN的安全威胁,解析电信诈骗的技术症结——By Me
查看>>
内部类演示
查看>>
多态/接口
查看>>
简单的proxy之TinyHTTPProxy.py
查看>>
正式开张
查看>>
java中的注解
查看>>
日期选择组件(DatePicker)的实现
查看>>
Java 求字符串中出现频率最高字符
查看>>