数论题\(n \leq 500\)肯定是什么暴力算法……
注意到每一个数\(> \sqrt{n}\)的因子最多只有一个,这意味着\(> \sqrt{n}\)的因子之间是独立的,而只有\(\leq \sqrt{n}\)的因子之间会相互影响。而\(\leq \sqrt{n}\)的因子只有\(2,3,5,7,11,13,17,19\)总共\(8\)个,所以可以大力状压。
将\(2-n\)之间的所有数质因数分解,记录其中\(<\sqrt{n}\)的因子的出现情况,按照\(> \sqrt{n}\)的因子分类,一组一组地加入并DP。设\(dp_{i,j,k}\)表示第一个人拥有的寿司中\(<\sqrt{n}\)的因子存在情况为\(i\),第二个人拥有的寿司中\(<\sqrt{n}\)的因子存在情况为\(j\),当前计算的\(> \sqrt{n}\)的因子的存在情况为\(k\)时的方案数,转移看当前寿司分给第一个人还是第二个人。没有\(> \sqrt{n}\)因子的数先单独做一次。
总复杂度\(O(3^8n)\)
#include<iostream>
#include<cstdio>
#include<vector>
//This code is written by Itst
using namespace std;
#define int long long
const int prm[] = {2,3,5,7,11,13,17,19};
int dp[1 << 8][1 << 8][3] , N , MOD;
vector < int > Max[507];
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
cin >> N >> MOD;
for(int i = 2 ; i <= N ; ++i){
int all = 0 , x = i;
for(int j = 7 ; j >= 0 ; --j){
all <<= 1;
if(x % prm[j] == 0){
while(x % prm[j] == 0)
x /= prm[j];
++all;
}
}
Max[x].push_back(all);
}
dp[0][0][0] = 1;
for(auto t : Max[1])
for(int i = (1 << 8) - 1 ; i >= 0 ; --i){
int s = ((1 << 8) - 1) ^ i , k = s;
while(1){
if(!(i & t))
dp[i][k | t][0] = (dp[i][k | t][0] + dp[i][k][0]) % MOD;
if(!(k & t))
dp[i | t][k][0] = (dp[i | t][k][0] + dp[i][k][0]) % MOD;
if(!k) break;
k = (k - 1) & s;
}
}
for(int p = 2 ; p <= N ; ++p)
if(!Max[p].empty()){
for(auto t : Max[p]){
for(int i = (1 << 8) - 1 ; i >= 0 ; --i){
int s = ((1 << 8) - 1) ^ i , k = s;
while(1){
if(!(i & t))
dp[i][k | t][1] = (dp[i][k | t][1] + dp[i][k][0] + dp[i][k][1]) % MOD;
if(!(k & t))
dp[i | t][k][2] = (dp[i | t][k][2] + dp[i][k][0] + dp[i][k][2]) % MOD;
if(!k) break;
k = (k - 1) & s;
}
}
}
for(int i = (1 << 8) - 1 ; i >= 0 ; --i){
int s = ((1 << 8) - 1) ^ i , k = s;
while(1){
dp[i][k][0] = (dp[i][k][0] + dp[i][k][1] + dp[i][k][2]) % MOD;
dp[i][k][1] = dp[i][k][2] = 0;
if(!k) break;
k = (k - 1) & s;
}
}
}
int sum = 0;
for(int i = (1 << 8) - 1 ; i >= 0 ; --i){
int s = ((1 << 8) - 1) ^ i , k = s;
while(1){
sum = (sum + dp[i][k][0]) % MOD;
if(!k) break;
k = (k - 1) & s;
}
}
cout << sum;
return 0;
}