洛谷P2150 寿司晚宴
解:发现每个质数只能属于一个人,于是想到每个质数有三种情况:属于a,属于b,都不属于。
然后考虑状压每个人的质数集合,可以得到30分。
转移就是外层枚举每个数,内层枚举每个人的状态,然后看能否转移。能转移就转移。
考虑优化:有个套路是大于√的质数最多只有一个。于是单独考虑那些,先把不含那些的转移出来放到数组f中。
然后每次外层枚举一个质数,中层枚举它的倍数,内层枚举两个人的状态。
每个质数可以属于a或者属于b或者都不属于。考虑到转移属于a的时候我们不可避免的会算到都不属于(除非再开一维记录),于是容斥一波。
属于a和属于b因为要分开转移多次(中层枚举倍数),于是用g,h数组分别转移。
最后f = g + h - f(容斥掉都不属于)。
其实感觉多开一维好想一点......。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 510, M = 267; 5 6 int n, sta[N], p[N], top, last[N], id[N], stk[N], tp; 7 LL f[2][M][M], g[2][M][M], MO, h[2][M][M], F[M][M]; 8 bool vis[N]; 9 10 inline void Add(LL &a, const LL &b) { 11 a += b; 12 while(a >= MO) a -= MO; 13 while(a < 0) a += MO; 14 return; 15 } 16 17 inline void getp(int n) { 18 for(int i = 2; i <= n; i++) { 19 if(!vis[i]) { 20 p[++top] = i; 21 id[i] = top; 22 last[i] = i; 23 } 24 for(int j = 1; j <= top && i * p[j] <= n; j++) { 25 vis[i * p[j]] = 1; 26 last[i * p[j]] = p[j]; 27 if(i % p[j] == 0) break; 28 } 29 } 30 return; 31 } 32 33 int main() { 34 35 //freopen("in.in", "r", stdin); 36 37 scanf("%d%lld", &n, &MO); 38 getp(n); 39 40 int m = 1; 41 while(m < top && p[m + 1] <= 19) m++; 42 int lm = 1 << m; 43 44 for(int i = 2; i <= n; i++) { 45 int x = i, y; 46 while(x > 1) { 47 y = last[x]; 48 if(id[y] <= m) sta[i] |= (1 << (id[y] - 1)); 49 else sta[i] |= (1 << m); 50 while(x % y == 0) x /= y; 51 } 52 } 53 54 55 LL ans = 0; 56 f[0][0][0] = 1; 57 for(int i = 2; i <= n; i++) { 58 memset(f[(i + 1) & 1], 0, sizeof(f[0])); 59 if((sta[i] & (lm - 1)) != sta[i]) { 60 stk[++tp] = i; 61 memcpy(f[(i + 1) & 1], f[i & 1], sizeof(f[i & 1])); 62 continue; 63 } 64 for(int s = 0; s < lm; s++) { 65 for(int t = 0; t < lm; t++) { 66 if((s & t) || (!f[i & 1][s][t])) continue; 67 /// f[i][s][t] 68 Add(f[(i + 1) & 1][s][t], f[i & 1][s][t]); 69 if((sta[i] & t) == 0) { 70 Add(f[(i + 1) & 1][s | sta[i]][t], f[i & 1][s][t]); 71 } 72 if((sta[i] & s) == 0) { 73 Add(f[(i + 1) & 1][s][t | sta[i]], f[i & 1][s][t]); 74 } 75 } 76 } 77 } 78 79 for(int s = 0; s < lm; s++) { 80 for(int t = 0; t < lm; t++) { 81 if(s & t) continue; 82 Add(F[s][t], f[(n + 1) & 1][s][t]); 83 } 84 } 85 86 for(int i = 1; i <= tp; i++) { 87 if(vis[stk[i]]) { 88 continue; 89 } 90 91 memcpy(g[1], F, sizeof(F)); 92 memcpy(h[1], F, sizeof(F)); 93 int time = 1; 94 for(int x = stk[i]; x <= n; x += stk[i], time++) { 95 memset(g[(time + 1) & 1], 0, sizeof(g[0])); 96 memset(h[(time + 1) & 1], 0, sizeof(h[0])); 97 98 for(int s = 0; s < lm; s++) { 99 for(int t = 0; t < lm; t++) { 100 if(s & t) continue; 101 Add(g[(time + 1) & 1][s][t], g[time & 1][s][t]); 102 Add(h[(time + 1) & 1][s][t], h[time & 1][s][t]); 103 if((sta[time] & t) == 0) { 104 Add(g[(time + 1) & 1][s | sta[time]][t], g[time & 1][s][t]); 105 } 106 if((sta[time] & s) == 0) { 107 Add(h[(time + 1) & 1][s][t | sta[time]], h[time & 1][s][t]); 108 } 109 } 110 } 111 } 112 for(int s = 0; s < lm; s++) { 113 for(int t = 0; t < lm; t++) { 114 if(s & t) continue; 115 F[s][t] = -F[s][t]; 116 Add(F[s][t], g[time & 1][s][t]); 117 Add(F[s][t], h[time & 1][s][t]); 118 } 119 } 120 } 121 122 for(int s = 0; s < lm; s++) { 123 for(int t = 0; t < lm; t++) { 124 if(s & t) continue; 125 Add(ans, F[s][t]); 126 } 127 } 128 129 printf("%lld\n", ans); 130 return 0; 131 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 510, M = 267; 5 6 int n, sta[N], p[N], top, last[N], id[N], stk[N], tp; 7 LL f[2][M][M], g[2][M][M][2], MO, h[2][M][M][2], F[M][M]; 8 bool vis[N]; 9 10 inline void Add(LL &a, const LL &b) { 11 a += b; 12 while(a >= MO) a -= MO; 13 while(a < 0) a += MO; 14 return; 15 } 16 17 inline void getp(int n) { 18 for(int i = 2; i <= n; i++) { 19 if(!vis[i]) { 20 p[++top] = i; 21 id[i] = top; 22 last[i] = i; 23 } 24 for(int j = 1; j <= top && i * p[j] <= n; j++) { 25 vis[i * p[j]] = 1; 26 last[i * p[j]] = p[j]; 27 if(i % p[j] == 0) break; 28 } 29 } 30 return; 31 } 32 33 int main() { 34 35 //freopen("in.in", "r", stdin); 36 37 scanf("%d%lld", &n, &MO); 38 getp(n); 39 40 int m = 1; 41 while(m < top && p[m + 1] <= 19) m++; 42 int lm = 1 << m; 43 44 for(int i = 2; i <= n; i++) { 45 int x = i, y; 46 while(x > 1) { 47 y = last[x]; 48 if(id[y] <= m) sta[i] |= (1 << (id[y] - 1)); 49 else sta[i] |= (1 << m); 50 while(x % y == 0) x /= y; 51 } 52 } 53 54 55 LL ans = 0; 56 f[0][0][0] = 1; 57 for(int i = 2; i <= n; i++) { 58 memset(f[(i + 1) & 1], 0, sizeof(f[0])); 59 if((sta[i] & (lm - 1)) != sta[i]) { 60 stk[++tp] = i; 61 memcpy(f[(i + 1) & 1], f[i & 1], sizeof(f[i & 1])); 62 continue; 63 } 64 for(int s = 0; s < lm; s++) { 65 for(int t = 0; t < lm; t++) { 66 if((s & t) || (!f[i & 1][s][t])) continue; 67 /// f[i][s][t] 68 Add(f[(i + 1) & 1][s][t], f[i & 1][s][t]); 69 if((sta[i] & t) == 0) { 70 Add(f[(i + 1) & 1][s | sta[i]][t], f[i & 1][s][t]); 71 } 72 if((sta[i] & s) == 0) { 73 Add(f[(i + 1) & 1][s][t | sta[i]], f[i & 1][s][t]); 74 } 75 } 76 } 77 } 78 79 for(int s = 0; s < lm; s++) { 80 for(int t = 0; t < lm; t++) { 81 if(s & t) continue; 82 Add(F[s][t], f[(n + 1) & 1][s][t]); 83 } 84 } 85 86 for(int i = 1; i <= tp; i++) { 87 if(vis[stk[i]]) { 88 continue; 89 } 90 91 //memcpy(g[1], F, sizeof(F)); 92 //memcpy(h[1], F, sizeof(F)); 93 for(int s = 0; s < lm; s++) { 94 for(int t = 0; t < lm; t++) { 95 g[1][s][t][0] = F[s][t]; 96 g[1][s][t][1] = 0; 97 h[1][s][t][0] = F[s][t]; 98 h[1][s][t][1] = 0; 99 } 100 } 101 102 int time = 1; 103 for(int x = stk[i]; x <= n; x += stk[i], time++) { 104 memset(g[(time + 1) & 1], 0, sizeof(g[0])); 105 memset(h[(time + 1) & 1], 0, sizeof(h[0])); 106 107 for(int s = 0; s < lm; s++) { 108 for(int t = 0; t < lm; t++) { 109 if(s & t) continue; 110 Add(g[(time + 1) & 1][s][t][0], g[time & 1][s][t][0]); 111 Add(g[(time + 1) & 1][s][t][1], g[time & 1][s][t][1]); 112 Add(h[(time + 1) & 1][s][t][0], h[time & 1][s][t][0]); 113 Add(h[(time + 1) & 1][s][t][1], h[time & 1][s][t][1]); 114 if((sta[time] & t) == 0) { 115 Add(g[(time + 1) & 1][s | sta[time]][t][1], g[time & 1][s][t][0]); 116 Add(g[(time + 1) & 1][s | sta[time]][t][1], g[time & 1][s][t][1]); 117 } 118 if((sta[time] & s) == 0) { 119 Add(h[(time + 1) & 1][s][t | sta[time]][1], h[time & 1][s][t][0]); 120 Add(h[(time + 1) & 1][s][t | sta[time]][1], h[time & 1][s][t][1]); 121 } 122 } 123 } 124 } 125 for(int s = 0; s < lm; s++) { 126 for(int t = 0; t < lm; t++) { 127 if(s & t) continue; 128 //F[s][t] = -F[s][t]; 129 //F[s][t] = 0; 130 Add(F[s][t], g[time & 1][s][t][1]); 131 Add(F[s][t], h[time & 1][s][t][1]); 132 } 133 } 134 } 135 136 for(int s = 0; s < lm; s++) { 137 for(int t = 0; t < lm; t++) { 138 if(s & t) continue; 139 Add(ans, F[s][t]); 140 } 141 } 142 143 printf("%lld\n", ans); 144 return 0; 145 }