[BZOJ4197][UOJ129][Noi2015]寿司晚宴(状压DP)
2018-03-17 18:01
447 查看
一、分析
讲真,这题看上去一点都不像状压。二、思路
显然,选了一个数,就相当于选了一个质因子集合。可以设状态:f[i][S1][S2]f[i][S1][S2]:到了第ii个数,第一个集合选取质因子的状态为S1S1(S1S1中包含kk表示第一个集合中有质因子kk,否则没有质因子kk),第二个集合选取质因子的状态为S2S2,但这样时空复杂度都难以承受……
而此题的思路是:凡是大于n−−√n的质因子,在[2,n][2,n]内的每个数都只出现一个。
所以可以考虑只压缩{2,3,5,7,11,13,17,19}{2,3,5,7,11,13,17,19}这个集合,这样复杂度就可以承受了。
三、预处理
先把数按一定的规则进行排序:给一个数定义一个关键码keyikeyi:数ii如果有大于1919的质因子,那么keyikeyi就等于这个质因子,否则keyi=1keyi=1。
然后把所有的数按照keykey排序。定义num[i]num[i]为排序后第ii个数。
然后分情况考虑:
四、如果第i+1i+1个数的关键码(keykey)等于11
(1)两个集合都不选num[i+1]num[i+1]:f[i+1][S1][S2]+=f[i][S1][S2]f[i+1][S1][S2]+=f[i][S1][S2]
(2)第一个集合选num[i+1]num[i+1]:
(如果S2S2和prinum[i+1]prinum[i+1]没有交集,prixprix为xx的质因子集合)
f[i+1][S1|prinum[i+1]][S2]+=f[i][S1][S2]f[i+1][S1|prinum[i+1]][S2]+=f[i][S1][S2]
(3)第二个集合选num[i+1]num[i+1]:
(如果S1S1和prinum[i+1]prinum[i+1]没有交集)
f[i+1][S1][S2|prinum[i+1]]+=f[i][S1][S2]f[i+1][S1][S2|prinum[i+1]]+=f[i][S1][S2]
五、如果第i+1i+1个数的关键码不为11
下面设关键码为RR。这时候要增设gg:
g[i][0][S1][S2]g[i][0][S1][S2]:到第ii个数,两个集合都没有质因子RR,两个集合状态为S1S1和S2S2。
g[i][1][S1][S2]g[i][1][S1][S2]:第一个集合包含质因子RR,同上。
g[i][2][S1][S2]g[i][2][S1][S2]:第二个集合包含质因子RR,同上。
具体地,从小到大,对11除外的每一种关键码进行DP(因为排序后关键码相同的数被分到了一个区间内)
设第ll个数到第rr个数的关键码为RR。那么先设:
g[l−1][0][S1][S2]=f[l−1][S1][S2]g[l−1][0][S1][S2]=f[l−1][S1][S2]
g[l−1][1][S1][S2]=g[l−1][2][S1][S2]=0g[l−1][1][S1][S2]=g[l−1][2][S1][S2]=0
同样与ff相似,但要注意质因子RR:
(1)不选num[i+1]num[i+1]:
g[i+1][a][S1][S2]+=g[i][a][S1][S2]g[i+1][a][S1][S2]+=g[i][a][S1][S2]
(2)选num[i+1]num[i+1]加入集合一:
(如果S2S2和prinum[i+1]prinum[i+1]没有交集)
g[i+1][1][S1|prinum[i+1]][S2]+=g[i][0][S1][S2]+g[i][1][S1][S2]g[i+1][1][S1|prinum[i+1]][S2]+=g[i][0][S1][S2]+g[i][1][S1][S2]
(3)选num[i+1]num[i+1]加入集合二:
(如果S1S1和prinum[i+1]prinum[i+1]没有交集)
g[i+1][2][S1][S2|prinum[i+1]]+=g[i][0][S1][S2]+g[i][2][S1][S2]g[i+1][2][S1][S2|prinum[i+1]]+=g[i][0][S1][S2]+g[i][2][S1][S2]
第一维DP到rr时就停止这一部分的DP,并令:
f[r][S1][S2]=∑a=02{g[r][a][S1][S2]}f[r][S1][S2]=∑a=02{g[r][a][S1][S2]}
六、Other
最后答案为∑f[n−1][S1][S2]∑f[n−1][S1][S2]。使用滚动数组优化空间。
由于S2S2必须是S1S1相对全集{2,3,5,7,11,13,17,19}{2,3,5,7,11,13,17,19}的补集的子集,
所以复杂度O(38×n)O(38×n)。
七、代码
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int C = 256, N = 502, M = 105; int n, m, pri[M], divi ; bool mark ; ll MX, f[2][C][C], g[2][3][C][C]; struct cyx { int x, d; } orz ; bool comp(cyx a, cyx b) {return a.d < b.d;} int main() { int i; cin >> n >> MX; for (int i = 2; i <= 22; i++) { if (mark[i]) continue; for (int j = i * i; j <= 500; j += i) mark[j] = 1; } for (int i = 2; i <= 500; i++) if (!mark[i]) pri[++m] = i; for (int i = 2; i <= n; i++) { orz[i - 1].x = i; orz[i - 1].d = 1; for (int j = 1; j <= 8; j++) if (i % pri[j] == 0) divi[i] |= 1 << j - 1; for (int j = 9; j <= m; j++) if (i % pri[j] == 0) {orz[i - 1].d = j; break;} } sort(orz + 1, orz + n, comp); f[0][0][0] = 1; for (i = 0; orz[i + 1].d == 1; i++) { int o = i & 1; for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { f[o ^ 1][j][k] = 0; if (k == 0) break; } for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { int S1 = j | divi[orz[i + 1].x], S2 = k | (divi[orz[i + 1].x]); f[o ^ 1][j][k] = (f[o ^ 1][j][k] + f[o][j][k]) % MX; if (!(S1 & k)) f[o ^ 1][S1][k] = (f[o ^ 1][S1][k] + f[o][j][k]) % MX; if (!(j & S2)) f[o ^ 1][j][S2] = (f[o ^ 1][j][S2] + f[o][j][k]) % MX; if (k == 0) break; } } for (; i < n - 1;) { int nxt = i + 1; while (orz[nxt + 1].d == orz[i + 1].d) nxt++; for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { g[i & 1][0][j][k] = f[i & 1][j][k]; g[i & 1][1][j][k] = g[i & 1][2][j][k] = 0; if (k == 0) break; } for (int h = i; h < nxt; h++) { int o = h & 1; for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { g[o ^ 1][0][j][k] = g[o ^ 1][1][j][k] = g[o ^ 1][2][j][k] = 0; if (k == 0) break; } for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { int S1 = j | divi[orz[h + 1].x], S2 = k | (divi[orz[h + 1].x]); g[o ^ 1][0][j][k] = (g[o ^ 1][0][j][k] + g[o][0][j][k]) % MX; g[o ^ 1][1][j][k] = (g[o ^ 1][1][j][k] + g[o][1][j][k]) % MX; g[o ^ 1][2][j][k] = (g[o ^ 1][2][j][k] + g[o][2][j][k]) % MX; if (!(S1 & k)) g[o ^ 1][1][S1][k] = (g[o ^ 1][1][S1][k] + g[o][0][j][k] + g[o][1][j][k]) % MX; if (!(j & S2)) g[o ^ 1][2][j][S2] = (g[o ^ 1][2][j][S2] + g[o][0][j][k] + g[o][2][j][k]) % MX; if (k == 0) break; } } for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { f[nxt & 1][j][k] = (g[nxt & 1][0][j][k] + g[nxt & 1][1][j][k] + g[nxt & 1][2][j][k]) % MX; if (k == 0) break; } i = nxt; } ll ans = 0; for (int j = 0; j < 256; j++) for (int k = 255 - j; ; k = (k - 1) & (255 - j)) { ans = (ans + f[n - 1 & 1][j][k]) % MX; if (k == 0) break; } cout << ans << endl; return 0; }
相关文章推荐
- [UOJ129][BZOJ4197][NOI2015]寿司晚宴(状压DP)
- 【bzoj4197】[Noi2015]寿司晚宴 状压DP
- bzoj 4197: [Noi2015]寿司晚宴 (状压DP)
- [bzoj4197][Noi2015]寿司晚宴【dp】
- NOI 2015 寿司晚宴 状压DP
- 4197: [Noi2015]寿司晚宴 思路题 状压DP
- [BZOJ 4197][Noi2015]寿司晚宴:状压DP
- 【uoj129】 NOI2015—寿司晚宴
- BZO4197 & 洛谷2150 & UOJ129:[NOI2015]寿司晚宴——题解
- BZOJ4197 / UOJ129 [Noi2015]寿司晚宴
- 【bzoj4197】[Noi2015]寿司晚宴 dp
- NOI2015 寿司晚宴 状压DP
- BZOJ 4197([Noi2015]寿司晚宴-状压dp)
- bzoj 4197: [Noi2015]寿司晚宴 状压dp
- 【bzoj4197】[Noi2015]寿司晚宴 分解质因数+状态压缩dp
- BZOJ 4197: [Noi2015]寿司晚宴 DP
- BZOJ 4197: [Noi2015]寿司晚宴( dp )
- bzoj4197 [Noi2015]寿司晚宴
- 【NOI2015】寿司晚会 题解(状压DP)
- BZOJ4197: [Noi2015]寿司晚宴 状压DP