LOJ #2131. 「NOI2015」寿司晚宴

<sqrt(500)的质数只有8个
直接状压
剩下的大质数相同的一起dp就行了。

CODE

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 505;
const int S = 256;
const int p[8] = { 2, 3, 5, 7, 11, 13, 17, 19 };
int mp[MAXN], cur, n, f[S][S], g[2][S][S], mod;
vector<int>vec[MAXN];

int main () {
	scanf("%d%d", &n, &mod);
	for(int i = 2; i <= n; ++i) {
		int s = 0, tmp = i;
		for(int j = 0; j < 8; ++j) {
			if(tmp % p[j] == 0) {
				while(tmp % p[j] == 0) tmp /= p[j];
				s |= 1<<j;
			}
		}
		vec[tmp==1?++cur:mp[tmp]?mp[tmp]:mp[tmp]=++cur].push_back(s);
	}
	f[0][0] = 1;
	for(int i = 1; i <= cur; ++i) {
		for(int j = 0; j < S; ++j)
			for(int k = 0; k < S; ++k)
				g[0][j][k] = g[1][j][k] = f[j][k];
		for(int o = vec[i].size()-1; ~o; --o)
			for(int j = S-1; ~j; --j)
				for(int k = S-1; ~k; --k)
					if((vec[i][o]&k) == 0) {
						(g[0][j|vec[i][o]][k] += g[0][j][k]) %= mod;
						
						(g[1][k][j|vec[i][o]] += g[1][k][j]) %= mod;
					}
		for(int j = 0; j < S; ++j)
			for(int k = 0; k < S; ++k)
				f[j][k] = (g[0][j][k] + g[1][j][k] - f[j][k]) % mod;
	}
	int ans = 0;
	for(int j = 0; j < S; ++j)
		for(int k = 0; k < S; ++k)
			(ans += f[j][k]) %= mod;
	printf("%d\n", (ans + mod) % mod);
}
posted @ 2019-12-14 14:50  _Ark  阅读(113)  评论(0编辑  收藏  举报