题目转化:将2~n的数分成两组,可以不选,使得这两组没有公共的质因子。求方案数。

选择了一个数,相当于选择了它的所有质因子。

30分:

发现,n<=30的时候,涉及到的质因子也就10个。2,3,5,7,11,13,19,23,29

直接状压。f[i][A][B] 前i个数,第一个人的质因子选择状态A,第二人B,的方案数。(第一维可以滚动,当然,可以倒序循环直接省略)

每个数质因数分解,前八个质因子,压成二进制数,转移直接按位或。

100分:

质因子太多状压不了。

公理:一个数>=sqrt(n)的质因子最多只有一个。(显然啊,否则质因数分解就超过了n)

所以,对于最大质因子>=sqrt(n)的数,根据最大质因子分类,质因子相同的,要么都考虑进入A,要么都考虑进入B,要么都不选。

设g[0/1][A][B]表示这一阶段,数字都考虑进入A/B的方案数。初值和f一样。

最后,f[A][B]=g[0][A][B]+g[1][A][B]-f[A][B] 因为,所有数都不选的方案计算了两次,所以减一次。

对于最大质因子<sqrt(n)的数,直接根据上面的转移就好。

统计答案时,选择A&B=0 的方案数。

具体看代码:(luogu要开O2)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
int n,mod;
struct node{
int has;
int z;
}num[N];
bool cmp(node a,node b){
return a.z<b.z;
}
ll ans;
int zh[N],cnt;
int ps[N],tot;
int vis[N];
bool in[N];
void sieve(){
for(int i=;i<=n;i++){
if(!vis[i]){
tot++;ps[tot]=i;
vis[i]=i;
}
for(int j=;j<=tot;j++){
if(i*ps[j]>n) break;
vis[i*ps[j]]=ps[j];
if(i%ps[j]==) break;
}
}
}
void sol(int x){
cnt=;
int kk=x;
for(int i=;i<=tot;i++){
if(x%ps[i]==){
zh[++cnt]=i;//prime's id
while(x%ps[i]==) x/=ps[i];
}
}
for(int i=;i<=cnt;i++){
if(zh[i]>) num[kk].z=zh[i];
else num[kk].has|=(<<zh[i]-);
}
if(!num[kk].z) num[kk].z=;
}
ll f[<<][<<];
ll g[][<<][<<];
int main()
{
scanf("%d%d",&n,&mod);
sieve();
for(int i=;i<=n;i++)sol(i);
sort(num+,num+n+,cmp);
f[][]=;
for(int i=;i<=n;i++){
if(num[i].z==){
for(int A=(<<)-;A>=;A--)
for(int B=(<<)-;B>=;B--){
f[A|num[i].has][B]=(f[A|num[i].has][B]+f[A][B])%mod;
f[A][B|num[i].has]=(f[A][B|num[i].has]+f[A][B])%mod;
}
}
else{
int zz=num[i].z;
memcpy(g[],f,sizeof f);
memcpy(g[],f,sizeof f);
while(num[i].z==zz&&i<=n){
for(int A=(<<)-;A>=;A--)
for(int B=(<<)-;B>=;B--){
g[][A|num[i].has][B]=(g[][A|num[i].has][B]+g[][A][B])%mod;
g[][A][B|num[i].has]=(g[][A][B|num[i].has]+g[][A][B])%mod;
}
i++;
}
i--;
for(int A=(<<)-;A>=;A--)
for(int B=(<<)-;B>=;B--){
f[A][B]=((g[][A][B]+g[][A][B])%mod-f[A][B])%mod;if(f[A][B]<) f[A][B]+=mod;
}
}
}
for(int A=;A<=(<<)-;A++)
for(int B=;B<=(<<)-;B++){
if((A&B)==) ans=(ans+f[A][B])%mod;
}
printf("%lld",ans);
return ;
}

总结:

这个题目其实很巧妙。

思路:

1.互质即没有公共质因子,所以选择一个数就是选择一些质因子。转化题意。

2.30分,发现质因子很小,可以直接状压。

3.100分,发现每个数>=sqrt的质因子最多只有一个。暴力分组考虑,每组内统计都放进A/B的方案。

关键的突破口还是题意的转化。以及第三点。

[NOI2015]寿司晚宴——状压dp的更多相关文章

  1. [NOI2015]寿司晚宴 --- 状压DP

    [NOI2015]寿司晚宴 题目描述 为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴. 小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿 ...

  2. 【BZOJ4197】[Noi2015]寿司晚宴 状压DP+分解质因数

    [BZOJ4197][Noi2015]寿司晚宴 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴 ...

  3. B4197 [Noi2015]寿司晚宴 状压dp

    这个题一开始想到了唯一分解定理,然后状压.但是显然数组开不下,后来想到每个数(n<500)大于19的素因子只可能有一个,所以直接单独存就行了. 然后正常状压dp就很好搞了. 题干: Descri ...

  4. bzoj4197 [Noi2015]寿司晚宴——状压DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4197 首先,两个人选的数都互质可以看作是一个人选了一个数,就相当于选了一个质因数集合,另一个 ...

  5. BZOJ 4197: [Noi2015]寿司晚宴 状压dp+质因数分解

    挺神的一道题 ~ 由于两个人选的数字不能有互质的情况,所以说对于一个质因子来说,如果 1 选了,则 2 不能选任何整除该质因子的数. 然后,我们发现对于 1 ~ 500 的数字来说,只可能有一个大于 ...

  6. 【BZOJ-4197】寿司晚宴 状压DP

    4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 694  Solved: 440[Submit][Status] ...

  7. BZOJ 4197 NOI 2015 寿司晚宴 状压DP

    4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 694  Solved: 440[Submit][Status] ...

  8. NOI 2015 寿司晚宴 (状压DP+分组背包)

    题目大意:两个人从2~n中随意取几个数(不取也算作一种方案),被一个人取过的数不能被另一个人再取.两个人合法的取法是,其中一个人取的任何数必须与另一个人取的每一个数都互质,求所有合法的方案数 (数据范 ...

  9. [NOI2015][bzoj4197] 寿司晚宴 [状压dp+质因数]

    题面 传送门 思路 首先,要让两个人选的数字全部互质,那么有一个显然的充要条件:甲选的数字的质因数集合和乙选的数字的质因数集合没有交集 30pt 这种情况下n<=30,也就是说可用的质数只有10 ...

随机推荐

  1. [React]全自动数据表格组件——BodeGrid

    表格是在后台管理系统中用的最频繁的组件之一,相关的功能有数据的新增和编辑.查询.排序.分页.自定义显示以及一些操作按钮.我们逐一深入进行探讨以及介绍我的设计思路:   新增和编辑 想想我们最开始写新增 ...

  2. CSharp 案例:用 Dynamic 来解决 DataTable 数值累加问题

    需求说明 给定一个 DataTable,如果从中取出数值类型列的值并对其累加? 限制:不知该列是何种数值类型. 解决方案 1.将表转换为 IEnumerable<dynamic>,而后获取 ...

  3. item 3: 理解decltype

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 decltype是一个奇怪的东西.给出一个名字或者一个表达式,de ...

  4. 在 Ionic2 TypeScript 项目中导入第三方 JS 库

    原文发表于我的技术博客 本文分享了在Ionic2 TypeScript 项目中导入第三方 JS 库的方法,供参考. 原文发表于我的技术博客 1. Typings 的方式 因在 TypeScript 中 ...

  5. Libp2p学习(一)

    Libp2p学习 参考资料:libp2p-specifications : https://github.com/libp2p/specs 持续更新ing 1. 介绍 Libp2p的实现目标是: 支持 ...

  6. “耐撕团队”部署并测试onezero团队记帐本项目

    耐撕团队 对onezero团队记帐本项目的部署并测试 测试指标参见下面给出的博客: http://www.ltesting.net/ceshi/ceshijishu/xncs/2014/1030/20 ...

  7. 作业七:Linux内核如何装载和启动一个可执行程序

    作业七:Linux内核如何装载和启动一个可执行程序 一.编译链接的过程和ELF可执行文件格式 可执行文件的创建——预处理.编译和链接 在object文件中有三种主要的类型. 一个可重定位(reloca ...

  8. Linux内核分析 期末总结

    Linux内核分析 期末总结 一.知识概要 1. 计算机是如何工作的 存储程序计算机工作模型:冯诺依曼体系结构 X86汇编基础 会变一个简单的C程序分析其汇编指令执行过程 2. 操作系统是如何工作的 ...

  9. Zookeeper 3.4.8分布式安装

    1.机器信息 五台centos 64位机器 2.集群规划 Server Name Hadoop Cluster Zookeeper   Ensemble HBase Cluster Hadoop01 ...

  10. layui使用记录

    一.layui表格渲染 如果后台返回的实力类里面包含另一个实体类,那么需要使用如下方式取出相应的值 var tableResult = table.render({ elem: '#' + Serve ...