UOJ#129. 【NOI2015】寿司晚宴

要求A,B选的数两两互质,其实就是把1~n的质因子分配给A,B两个人(可以都不给)
一种朴素的想法是直接状压所有质因子, O ( n 2 n )
注意到实际上在一个数中 > n 的因子至多只会有1个,把他们压到状态里很浪费,而 < n 的因子最多8个,我们状压这8个质因子, > n 的质因子互相独立,对他们分开dp

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
using namespace std;

const int maxn = 510;
const int mask = 1<<8;

int p[maxn],pri,xp[maxn],v[maxn];
int cov[maxn];
vector<int>V[maxn];
void get_prime()
{
    for(int i=2;i<maxn;i++)
    {
        if(!v[i]) xp[i]=i,p[++pri]=i;
        for(int j=1,k=p[j]*i;k<maxn;j++,k=p[j]*i)
        {
            xp[k]=xp[i]; v[k]=1;
            if(i%p[j]==0) break;
        }
    }
    for(int i=2;i<maxn;i++)
    {
        for(int j=1;j<=8;j++) if(i%p[j]==0) cov[i]|=1<<j-1;
        if(xp[i]>p[8]) V[xp[i]].pb(i);
        else V[i].pb(i);
    }
}

int n,mod;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}

int f[mask][mask],g0[2][mask][mask],g1[2][mask][mask];

int main()
{
    get_prime();

    scanf("%d%d",&n,&mod);

    f[0][0]=1; int S=(1<<8)-1;
    for(int i=n;i>=2;i--) if(V[i].size())
    {
        int now=0;
        for(int s1=0;s1<=S;s1++)
        {
            int oth=S-s1;
            for(int s2=oth;;s2=(s2-1)&oth)
            {
                g0[now][s1][s2]=g1[now][s1][s2]=f[s1][s2];
                g0[!now][s1][s2]=g1[!now][s1][s2]=0;
                if(!s2) break;
            }
        }
        for(int j=0;j<(int)V[i].size();j++) if(V[i][j]<=n)
        {
            int x=V[i][j]; now=!now;
            for(int s1=0;s1<=S;s1++)
            {
                int oth=S-s1;
                for(int s2=oth;;s2=(s2-1)&oth)
                {
                    int &t1=g0[!now][s1][s2];
                    add(g0[now][s1][s2],t1);
                    if(!(cov[x]&s2)) add(g0[now][s1|cov[x]][s2],t1);
                    t1=0;

                    int &t2=g1[!now][s1][s2];
                    add(g1[now][s1][s2],t2);
                    if(!(cov[x]&s1)) add(g1[now][s1][s2|cov[x]],t2);
                    t2=0;
                    if(!s2) break;
                }
            }
        }
        for(int s1=0;s1<=S;s1++)
        {
            int oth=S-s1;
            for(int s2=oth;;s2=(s2-1)&oth)
            {
                f[s1][s2]=(g0[now][s1][s2]+g1[now][s1][s2]-f[s1][s2])%mod;
                if(f[s1][s2]<0) f[s1][s2]+=mod;
                if(!s2) break;
            }
        }
    }

    int ans=0;
    for(int s1=0;s1<=S;s1++)
    {
        int oth=S-s1;
        for(int s2=oth;;s2=(s2-1)&oth)
        {
            add(ans,f[s1][s2]);
            if(!s2) break;
        }
    }
    printf("%d\n",ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/l_0_forever_lf/article/details/80329839