这题现场想的思路方向都是对的,但限于现场和实力因素没能A

很显然我们会想到质因数的选取

如果某个质数p被W选了,那G就不能选含有质因子p的数

因此我们不难想到状压质数的选取情况,令f[i][j]为w质数选取状态为i,g质数选取状态j的方案数

但是500以内质数太多了怎么办?我们考虑大质数能不能分开考虑

考虑到sqrt(500)以外的质数,他们在每个数中最多出现一次,因此我们只要按这些质数分类做dp即可

这样需要状压的质数只有2,3,5,7,11,13,17,23这8个了,这样就可以解决了

具体的,我用state表示每个数前8个质数的含有情况,res表示除去前8个质数剩下的数

然后按照res排序做dp即可

 1 #include<iostream>
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<stdlib.h>
 6 #include<algorithm>
 7 
 8 using namespace std;
 9 const int sp[8]={2,3,5,7,11,13,17,19};
10 struct node{int res,st;} a[510];
11 
12 int f[256][256],g[2][256][256];
13 int ans,n,p;
14 bool cmp(node a,node b)
15 {
16      return a.res<b.res;
17 }
18 int main()
19 {
20     scanf("%d%d",&n,&p);
21     for (int i=2; i<=n; i++)
22     {
23         int x=i;
24         for (int j=0; j<8; j++)
25           if (x%sp[j]==0)
26           {
27              a[i].st+=1<<j;
28              while (x%sp[j]==0) x/=sp[j];
29           } 
30         a[i].res=x;
31     }  
32     sort(a+2,a+1+n,cmp);
33     f[0][0]=g[0][0][0]=g[1][0][0]=1;
34     for (int i=2; i<=n; i++)
35     { 
36         memcpy(g[0],f,sizeof(f));
37         memcpy(g[1],f,sizeof(f));
38         for (int u=0; u<256; u++)
39           for (int v=0; v<256; v++)
40             if ((u&v)==0)
41             {
42                 if ((a[i].st&v)==0) g[0][u|a[i].st][v]=(g[0][u|a[i].st][v]+f[u][v])%p;
43                 if ((a[i].st&u)==0) g[1][u][v|a[i].st]=(g[1][u][v|a[i].st]+f[u][v])%p;             
44             }
45         
46         if (a[i].res!=1)
47         {
48            int j;
49            for (j=i+1; j<=n&&a[j].res==a[i].res; j++)
50              for (int u=255;u>=0;u--)
51                for (int v=255;v>=0;v--)
52                  if ((u&v)==0)
53                  {
54                     if ((a[j].st&v)==0) g[0][u|a[j].st][v]=(g[0][u|a[j].st][v]+g[0][u][v])%p;
55                     if ((a[j].st&u)==0) g[1][u][v|a[j].st]=(g[1][u][v|a[j].st]+g[1][u][v])%p;             
56                  }        
57            i=j-1;
58         }
59         for (int u=0; u<256; u++)
60           for (int v=0; v<256; v++)
61             f[u][v]=((g[0][u][v]+g[1][u][v]-f[u][v])%p+p)%p;
62     }
63     for (int i=0; i<=255; i++)
64       for (int j=0; j<=255; j++)
65         if ((i&j)==0) ans=(ans+f[i][j])%p;
66     printf("%d\n",ans);
67     return 0;
68 }
View Code

 

posted on 2016-07-10 20:50  acphile  阅读(236)  评论(0编辑  收藏  举报