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
  • 相关阅读:
    python中的编码问题
    CVPR2018 Tutorial 之 Visual Recognition and Beyond
    hdu 1376 Octal Fractions
    hdu 1329 Hanoi Tower Troubles Again!
    hdu 1309 Loansome Car Buyer
    hdu 1333 Smith Numbers
    hdu 1288 Hat's Tea
    hdu 1284 钱币兑换问题
    hdu 1275 两车追及或相遇问题
    hdu 1270 小希的数表
  • 原文地址:https://www.cnblogs.com/Blue233333/p/9286405.html
Copyright © 2011-2022 走看看