洛谷P2150 寿司晚宴

解:发现每一个质数只能属于一我的,因而想到每一个质数有三种状况:属于a,属于b,都不属于。c++

而后考虑状压每一个人的质数集合,能够获得30分。数组

转移就是外层枚举每一个数,内层枚举每一个人的状态,而后看可否转移。能转移就转移。ide

考虑优化:有个套路是大于√的质数最多只有一个。因而单独考虑那些,先把不含那些的转移出来放到数组f中。优化

而后每次外层枚举一个质数,中层枚举它的倍数,内层枚举两我的的状态。spa

每一个质数能够属于a或者属于b或者都不属于。考虑到转移属于a的时候咱们不可避免的会算到都不属于(除非再开一维记录),因而容斥一波。3d

属于a和属于b由于要分开转移屡次(中层枚举倍数),因而用g,h数组分别转移。code

最后f = g + h - f(容斥掉都不属于)。blog

其实感受多开一维好想一点......。get

  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 }
AC代码(容斥)
  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 }
AC代码(多开一维)