并不对劲的bzoj4197:loj2131:uoj129:p2150:[NOI2015]寿司晚宴

题目大意

有两个集合\(S_1,S_2 \subseteq [2,n] (n\leq 500)\),且对于\(\forall x\in S_1,y\in S_2 , gcd(x,y)=1\)
\(S_1,S_2\)有多少种方案
两种方案不同,当且仅当 方案一的\(S_1\)与方案二的\(S_1\)存在一个元素不同 或 方案一的\(S_2\)与方案二的\(S_2\)存在一个元素不同

题解

\(n\leq 100\)时,设\(f(A_1,A_2)\)表示当\(S_1\)中所有数的质因子集合为\(A_1\)\(S_2\)中所有数的质因子集合为\(A_2\)时的方案数,枚举2到\(n\)的每个数放到哪个集合里,直接dp
\(n\leq 500\)时,发现对于每个大于\(\sqrt{n}\)的质数,它作为质因子时的幂次数不超过一
那么对于每个大于\(\sqrt{n}\)的质数,枚举包含它的所有数都被分到\(S_1\)还是\(S_2\),设\(g(i,A_1,A_2)\)表示当包含当前枚举的这个质因数的数都在\(S_i\)里,\(S_1\)中所有数的质因子集合为\(A_1\)\(S_2\)中所有数的质因子集合为\(A_2\)时的方案数,还是直接dp

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 510
#define maxs ((1<<8)+7)
#define LL long long
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
void write(int x)
{
    if(x==0){putchar('0'),putchar('\n');return;}
    int f=0;char ch[20];
    if(x<0)putchar('-'),x=-x;
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
    return;
}
int n,mod,no[maxn],p[maxn],cntp,bul[maxn][maxn],son[maxn],f[maxs][maxs],f1[maxs][maxs],vis[maxn],f2[maxs][maxs];
signed main()
{
    n=read(),mod=read();
    rep(i,2,n)
        if(!no[i])
        {
            p[++cntp]=i;
            for(int j=i+i;j<=n;j+=i)no[j]=1;	
        }
    rep(i,2,n)
    {
        int lim=min(8,cntp);
        rep(j,1,lim)if(i%p[j]==0)son[i]|=(1<<(j-1));
        int f=8;
        for(int j=9;j<=cntp&&p[j]<=i;j++)if(i%p[j]==0){f=j;break;}
        bul[f][++bul[f][0]]=i;
    }
    int fulls=(1<<8)-1;f[0][0]=1;
    rep(j,1,bul[8][0])
    {
        int num=bul[8][j];
        dwn(s1,fulls,0)
            dwn(s2,fulls,0)
            {
                if(!(son[num]&s2))(f[s1|son[num]][s2]+=f[s1][s2])%=mod;
                if(!(son[num]&s1))(f[s1][s2|son[num]]+=f[s1][s2])%=mod;
            }
    }
    rep(i,9,cntp)
    {
        if(bul[i][0])memcpy(f1,f,sizeof(f)),memcpy(f2,f,sizeof(f));
        rep(j,1,bul[i][0])
        {
            int num=bul[i][j];
            dwn(s1,fulls,0)
                dwn(s2,fulls,0)
                {
                    if(!(son[num]&s2))(f1[s1|son[num]][s2]+=f1[s1][s2])%=mod;
                    if(!(son[num]&s1))(f2[s1][s2|son[num]]+=f2[s1][s2])%=mod;
                }
        }
        if(bul[i][0])rep(s1,0,fulls)rep(s2,0,fulls)f[s1][s2]=((f1[s1][s2]+f2[s1][s2]-f[s1][s2])%mod+mod)%mod;//既不放1号集合也不放2号集合的情况算重复了,要减去
    }
    int ans=0;
    rep(s1,0,fulls)rep(s2,0,fulls)(ans+=f[s1][s2])%=mod;
    write(ans);
    return 0;
}
posted @ 2019-02-17 18:25  echo6342  阅读(135)  评论(0编辑  收藏  举报