zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    114     return 0;
    115 }
    View Code
  • 相关阅读:
    se 键盘鼠标操作事件
    警告框操作方法(alert弹窗)
    se自带截图方法
    CSS Selector 高级用法
    吃奶酪
    互不侵犯
    hdu1102
    P4744 Iron man
    玉米田
    状压dp题单
  • 原文地址:https://www.cnblogs.com/Blue233333/p/9286405.html
Copyright © 2011-2022 走看看