BZOJ 4197: [Noi2015]寿司晚宴
状压<=sqrt(n)的所有质因数
对所有数分解质因数,大于sqrt(n)的质因数最多出现一次
包含相同大于sqrt(n)的质因数的数应该都归属于同一个人
按大于sqrt(n)的质因数排序
F[X][Y]表示两个人小于sqrt(n)的质因数的选取情况
G[0/1][X][Y]用于转移包含相同的大于sqrt(n)的质因子的数
精妙之处在于用状压然后分类避免了质因数之间相互影响的情况
#include<cstdio>
#include<algorithm>
using namespace std;
int n,mod,F[305][305],G[2][305][305];
int prime[8]={2,3,5,7,11,13,17,19};
struct node{
int S,val;
}E[505];
bool cmp(node a,node b){
return a.val<b.val;
}
int main(){
scanf("%d%d",&n,&mod);
for (int i=2; i<=n; i++){
int x=i;
for (int j=0; j<8; j++)
if (x%prime[j]==0){
E[i-1].S|=1<<j;
while (x%prime[j]==0) x/=prime[j];
}
E[i-1].val=x;
}
n--;
sort(E+1,E+n+1,cmp);
F[0][0]=1;
int N=8;
for (int i=1; i<=n; i++){
if (E[i].val==1 || E[i].val!=E[i-1].val){
for (int X=0; X<(1<<N); X++)
for (int Y=0; Y<(1<<N); Y++)
G[0][X][Y]=G[1][X][Y]=F[X][Y];
}
for (int X=(1<<N)-1; X>=0; X--)
for (int Y=(1<<N)-1; Y>=0; Y--)
if (!(X&Y)){
if (!(E[i].S&Y)) (G[0][X|E[i].S][Y]+=G[0][X][Y])%=mod;
if (!(E[i].S&X)) (G[1][X][Y|E[i].S]+=G[1][X][Y])%=mod;
}
if (E[i].val==1 || E[i].val!=E[i+1].val){
for (int X=0; X<(1<<N); X++)
for (int Y=0; Y<(1<<N); Y++)
if (!(X&Y)) F[X][Y]=((G[0][X][Y]+G[1][X][Y]-F[X][Y])%mod+mod)%mod;
}
}
int ans=0;
for (int X=0; X<(1<<N); X++)
for (int Y=0; Y<(1<<N); Y++)
if (!(X&Y)) (ans+=F[X][Y])%=mod;
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号