LOJ#2131. 「NOI2015」寿司晚宴

$n \leq 500$,$2-n$这些数字,两个人挑,可以重复挑,问有几种方案中,一个人选的所有数字与另一个人选的所有数字都互质。

不像前两题那么抠脚。。

如果$n$比较小的话,可以把两个人选的数字对应的质因子状压一下,$f(i,j,k)$--前$i$个数,第一个人选状态$j$,第二个人选状态$k$,状态表示质因子。

质因子的根号相关性质:根号n之后的每个质因子最多只会在一个数里出现一次。也就是说,对根号n前面的质因子我们是可能一次选若干种的,但根号n后面的每个质因子每次只能选一种,所以可以单独枚举,再用根号n以前的状态表示。$g(i,j,k)$--前$i$个含质数$p$的数,只让第一个人选,第二个人保持状态$k$的方案数;$h(i,j,k)$--前$i$个含质数$p$的数,只让第二个人选,第一个人保持状态$j$的方案数。如此dp完,$ans(j,k)$表示最后的$f(i,j,k)$,那么$ans(j,k)=g(t,j,k)+h(t,j,k)-ans(j,k)$,其中$t$表示含质因数$p$的数的个数,因为两个人都不选的方案算了两次。

  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 //#include<math.h>
  5 //#include<set>
  6 //#include<queue>
  7 //#include<bitset>
  8 //#include<vector>
  9 #include<algorithm>
 10 #include<stdlib.h>
 11 using namespace std;
 12 
 13 #define LL long long
 14 int qread()
 15 {
 16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
 17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
 18 }
 19 
 20 //Pay attention to '-' , LL and double of qread!!!!
 21 
 22 int n,mod;
 23 #define maxn 555
 24 int f[2][maxn][maxn],g[2][maxn][maxn],h[2][maxn][maxn],cur=0;
 25 
 26 int prime[maxn],lp,xx[maxn],ss[maxn]; bool notprime[maxn];
 27 void makeprime()
 28 {
 29     ss[2]=0; ss[3]=1; ss[5]=2; ss[7]=3;
 30     ss[11]=4; ss[13]=5; ss[17]=6; ss[19]=7;
 31     for (int i=2;i<=n;i++)
 32     {
 33         if (!notprime[i]) {prime[++lp]=i; xx[i]=i;}
 34         for (int j=1,tmp;j<=lp && 1ll*i*prime[j]<=n;j++)
 35         {
 36             notprime[tmp=i*prime[j]]=1;
 37             xx[tmp]=prime[j];
 38             if (!(i%prime[j])) break;
 39         }
 40     }
 41 }
 42 
 43 int num[maxn],len; int S,P;
 44 void mm(int x)
 45 {
 46     len=0;
 47     while (x>1) {num[++len]=xx[x]; x/=xx[x];}
 48     sort(num+1,num+1+len); len=unique(num+1,num+1+len)-num-1;
 49     S=0; for (int i=1;i<=len;i++) if (num[i]<=19) S|=1<<ss[num[i]];
 50     if (num[len]>19) P=num[len]; else P=0;
 51 }
 52 
 53 int list[maxn][maxn];
 54 void play(int &x,int v) {x+=v; x-=x>=mod?mod:0;}
 55 int main()
 56 {
 57     n=qread(); mod=qread();
 58     makeprime();
 59     for (int i=2;i<=n;i++) {mm(i); list[P][++list[P][0]]=S;}
 60     
 61     int ts=1<<8; f[0][0][0]=1; cur=0;
 62     for (int i=1;i<=list[0][0];i++)
 63     {
 64         int u=list[0][i];
 65         memset(f[cur^1],0,sizeof(f[cur^1]));
 66         for (int j=0;j<ts;j++)
 67             for (int k=0;k<ts;k++) if (f[cur][j][k])
 68             {
 69                 play(f[cur^1][j][k],f[cur][j][k]);
 70                 int nj=j|u; if ((nj&k)==0) play(f[cur^1][nj][k],f[cur][j][k]);
 71                 int nk=k|u; if ((j&nk)==0) play(f[cur^1][j][nk],f[cur][j][k]);
 72             }
 73         cur^=1;
 74     }
 75     
 76     for (int j=0;j<ts;j++)
 77         for (int k=0;k<ts;k++)
 78             f[0][j][k]=f[cur][j][k];
 79     for (int i=2;i<=n;i++) if (!notprime[i])
 80     {
 81         cur=0;
 82         for (int j=0;j<ts;j++)
 83             for (int k=0;k<ts;k++)
 84                 g[0][j][k]=f[0][j][k],h[0][j][k]=f[0][j][k];
 85         for (int t=1;t<=list[i][0];t++)
 86         {
 87             int u=list[i][t];
 88             memset(g[cur^1],0,sizeof(g[cur^1]));
 89             memset(h[cur^1],0,sizeof(h[cur^1]));
 90             for (int j=0;j<ts;j++)
 91                 for (int k=0;k<ts;k++) if (g[cur][j][k])
 92                 {
 93                     play(g[cur^1][j][k],g[cur][j][k]);
 94                     int nj=j|u; if ((nj&k)==0) play(g[cur^1][nj][k],g[cur][j][k]);
 95                 }
 96             for (int j=0;j<ts;j++)
 97                 for (int k=0;k<ts;k++) if (h[cur][j][k])
 98                 {
 99                     play(h[cur^1][j][k],h[cur][j][k]);
100                     int nk=k|u; if ((j&nk)==0) play(h[cur^1][j][nk],h[cur][j][k]);
101                 }
102             cur^=1;
103         }
104         for (int j=0;j<ts;j++)
105             for (int k=0;k<ts;k++)
106                 f[0][j][k]=((g[cur][j][k]+h[cur][j][k]-f[0][j][k])%mod+mod)%mod;
107     }
108     
109     int ans=0;
110     for (int j=0;j<ts;j++)
111         for (int k=0;k<ts;k++)
112             play(ans,f[0][j][k]);
113     printf("%d\n",ans);
114     return 0;
115 }
View Code

 

posted @ 2018-07-10 07:18  Blue233333  阅读(219)  评论(0编辑  收藏  举报