【状压DP】【cofun1623】寿司晚宴
来源:互联网 发布:网络文明志愿者注册 编辑:程序博客网 时间:2024/04/29 12:14
【cofun1623】寿司晚宴
Sample Input
输入样例1
3 10000
输入样例2
4 10000
输入样例3
100 100000000
Sample Output
样例输出1
9
样例输出2
21
样例输出3
3107203
Hint
分析:
题意:把一个数的集合分为两个集合,记为G,M,
显然,G中数的质因子与M中数的质因子应互不相同,因此选了一个数等同于选择了它的质因子。
虽然2<=n<=500,数据比较大,但是经过计算,我们会发现每个数最多只能有一个>=n√ 的质因子,其余质因子都<n√ ;而<n√ 的质数只有8个,加上对题目理解,可以考虑状压DP。- 把每个数中<
500−−−√ 的质因子压进二进制数中,并把它>=500−−−√ 的质因子记录下来。 - 按照最大质因子的大小给寿司排序,方便DP。
- 状压DP:
令f[i][j]表示集合G中质因子状态为i,集合M中质因子状态为j的方案数;dp[0][i][j]表示新出现的大质数归入集合G,原先G状态为i,M状态为j的方案数;dp[1][i][j]表示新出现的大质数归入集合M,原先G状态为i,M状态为j的方案数;
当枚举到新的大质数时,分情况,即不归入(不DP),归入G和归入M,可平行状压DP;
当含该新大质数的状态枚举完后,应将dp[0][i][j]和dp[1][i][j]归并为f[i][j],注意归并时因dp[0][i][j]和dp[1][i][j]都包含了不归入新的大质数的状态,应再减去一次,因类似背包,直接-f[i][j]即可。
注意:运用背包思想降了一维是表示当前枚举到第几个大质数,所以dp转移时要倒序。
具体转移方程在代码中注解。【因为比较多判断条件,会影响美观XDDD
- 把每个数中<
【做这题的时候看了dalao们的题解,感觉不是很能理解,还是自己打舒服~
- 代码:
#include <bits/stdc++.h> using namespace std; const int su[8] = {2, 3, 5, 7, 11, 13, 17, 19}; struct info{ int da, su; }e[505]; long long n, m, p, i, j, k, ans, dp[2][1 << 8][1 << 8], f[1 << 8][1 << 8]; inline int read() { long long x = 0, w = 1; char ch = 0; while(ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * w; } //读入优化 inline void write(long long x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); }//输出优化 bool cmp(info a, info b) { return a.da < b.da || (a.da == b.da && a.su < b.su); } int main() { n = read(), p = read(); //读入 for(i = 2; i <= n; i ++) { m ++; for(j = 0, k = i; j < 8; j ++) if (k % su[j] == 0) { for(; k % su[j] == 0; k /= su[j]); e[m].su |= (1 << j); } e[m].da = k; } sort(e + 1, e + m + 1, cmp); //把美味度的质因子压进二进制并按大质数排序1.&2. f[0][0] = 1; for(i = 1; i <= m; i ++) { if (e[i].da == 1 || e[i].da != e[i - 1].da) { memcpy(dp[0], f, sizeof(f)); memcpy(dp[1], f, sizeof(f)); } //新出现的大质数不归入集合G与M for(j = (1 << 8) - 1; j >= 0; j --) for(k = (1 << 8) - 1; k >= 0; k --) { if (! (e[i].su & k)) dp[0][j | e[i].su][k] = (dp[0][j | e[i].su][k] + dp[0][j][k]) % p; //新出现的大质数归入集合G if (! (e[i].su & j)) dp[1][j][k | e[i].su] = (dp[1][j][k | e[i].su] + dp[1][j][k]) % p; //新出现的大质数归入集合M } //新出现的大质数归入集合G或M,同时将小质数的状态进行状压DP if (e[i].da == 1 || e[i].da != e[i + 1].da) for(j = 0; j < 1 << 8; j ++) for(k = 0; k < 1 << 8; k ++) f[j][k] = ((dp[0][j][k] - f[j][k]) % p + dp[1][j][k] + p) % p; //将两种平行的情况归并 } //DP3. for(j = 0; j < 1 << 8; j ++) for(k = 0; k < 1 << 8; k ++) if (! (j & k)) ans = (ans + f[j][k]) % p; //统计答案 write(ans); //输出 return 0; }
下午好咩咩咩鹿啦啦~
已经晚上19:23了,上来抒发一下内心的咩咩皮(MMP),我在下一篇【队伍统计】中写跟同学讲了蛮久的寿司晚宴,然后,刚刚才帮他把这题啪对。。很多小细节都会导致致命的错误,他居然在转移方程里多了个+号,看了贼久ODX所以做题时一定要仔细啊!!!!!
阅读全文
0 0
- 【状压DP】【cofun1623】寿司晚宴
- 【NOI2015】【寿司晚宴】【状压DP】
- NOI2015 寿司晚宴 状压DP
- 【bzoj4197】[Noi2015]寿司晚宴 状压DP
- 【BZOJ4197】[Noi2015]寿司晚宴【状压DP】【背包】
- bzoj 4197: [Noi2015]寿司晚宴 状压dp
- [NOI2015][BZOJ4197][状压DP]寿司晚宴
- bzoj4197[Noi2015]寿司晚宴 [状压DP]
- bzoj4197 [NOI2015] [状压dp] 寿司晚宴
- NOI 2015 寿司晚宴 状压DP
- NOI 2015 寿司晚宴 状压DP
- BZOJ4197: [Noi2015]寿司晚宴 状压DP
- [BZOJ 4197][Noi2015]寿司晚宴:状压DP
- BZOJ 4197([Noi2015]寿司晚宴-状压dp)
- BZOJ 4197 寿司晚宴 (状压dp)
- 【bzoj4197】[Noi2015]寿司晚宴 dp
- 4197: [Noi2015]寿司晚宴 思路题 状压DP
- 【NOI2015】【bzoj4197】【状压DP】【滚动数组】寿司晚宴
- 44、NLP的其他分词功能测试
- system(“color 5f”)
- 缓存穿透和缓存失效的预防和解决
- 45、Docker 加 tensorflow的机器学习入门初步
- 46、tensorflow入门初步,手写识别0,1,2,3,4,5,6
- 【状压DP】【cofun1623】寿司晚宴
- 49、word2vec
- 1009. 说反话 (20)
- 48、tensorflow入门二,线性模型的拟合
- render: h => h(App) 是什么意思?
- 50、matplotlib画图示例
- OOP几大原则
- 51、tf-idf值提取关键词
- 52、saleforce 第一篇