• [BZOJ4197][Noi2015]寿司晚宴


    4197: [Noi2015]寿司晚宴

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 412  Solved: 279
    [Submit][Status][Discuss]

    Description

    为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴。小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴。

    在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 1,2,3,…,n−1,其中第 i 种寿司的美味度为 i+1 (即寿司的美味度为从 2 到 n)。
    现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小 G 品尝的寿司种类中存在一种美味度为 x 的寿司,小 W 品尝的寿司中存在一种美味度为 y 的寿司,而 x 与 y 不互质。
    现在小 G 和小 W 希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数 p 取模)。注意一个人可以不吃任何寿司。
     

    Input

    输入文件的第 1 行包含 2 个正整数 n,p,中间用单个空格隔开,表示共有 n 种寿司,最终和谐的方案数要对 p 取模。

     

    Output

    输出一行包含 1 个整数,表示所求的方案模 p 的结果。

     

    Sample Input

    3 10000

    Sample Output

    9

    HINT

     2≤n≤500


    0<p≤1000000000

    Source

     
    [Submit][Status][Discuss]


    HOME Back

    30分做法:

    考虑对于每个质数状压DP,f[i][j]表示第一个人选取集合为i,第二个人选取集合为j的方案数。比较简单的DP。

    100分做法:

    对于大于$sqrt n$的质数,每个数至多包含1个这样的因子,所以可以对小于$sqrt n$的质数,这样的数至多有8个。

    对于每个数,对其大于$sqrt n$的质因子分类,分别做DP即可。dp[i][j][2]表示第一个人选取集合为i,第二个人选取集合为j,质因子分给第i个人的方案数。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define ll long long
     4 using namespace std;
     5 int f[1<<8][1<<8],n,mod,dp[1<<8][1<<8][2];
     6 int prime[]={2,3,5,7,11,13,17,19},tot,ans;
     7 struct node{int p,S;}a[505];
     8 bool operator<(node x,node y){return x.p<y.p;}
     9 inline void solve(int x)
    10 {
    11     int now=0;
    12     for(int i=0;i<8;i++)
    13     if(!(x%prime[i]))
    14     {
    15         now|=1<<i;
    16         while(!(x%prime[i]))x/=prime[i];
    17     }
    18     a[++tot]=(node){x,now};
    19 }
    20 int main()
    21 {
    22     scanf("%d%d",&n,&mod);
    23     f[0][0]=1;
    24     for(int i=2;i<=n;i++)solve(i);
    25     sort(a+1,a+tot+1);
    26     for(int l=1,r;l<=tot;l=r+1)
    27     {
    28         for(r=l;r<tot&&a[r+1].p==a[r].p&&a[r].p!=1;r++);
    29         for(int i=0;i<256;i++)
    30         for(int j=0;j<256;j++)
    31         dp[i][j][0]=dp[i][j][1]=f[i][j];
    32         for(int k=l;k<=r;k++)
    33         {
    34             for(int i=255;~i;i--)
    35             {
    36                 int now=255-i;
    37                 for(int j=now;;j=(j-1)&now)
    38                 {
    39                     if((a[k].S&j)==0)
    40                     {
    41                         dp[i|a[k].S][j][0]+=dp[i][j][0];
    42                         if(dp[i|a[k].S][j][0]>=mod)
    43                         dp[i|a[k].S][j][0]-=mod;
    44                     }
    45                     if((a[k].S&i)==0)
    46                     {
    47                         dp[i][j|a[k].S][1]+=dp[i][j][1];
    48                         if(dp[i][j|a[k].S][1]>=mod)
    49                         dp[i][j|a[k].S][1]-=mod;
    50                     }
    51                     if(!j)break;
    52                 }
    53             }
    54         }
    55         for(int i=0;i<256;i++)
    56         for(int j=0;j<256;j++)
    57         {
    58             f[i][j]=dp[i][j][0]+dp[i][j][1]-f[i][j];
    59             if(f[i][j]>=mod)f[i][j]-=mod;
    60             if(f[i][j]<0)f[i][j]+=mod;
    61         }
    62     }
    63     for(int i=0;i<256;i++)
    64     {
    65         int now=255-i;
    66         for(int j=now;;j=(j-1)&now)
    67         {
    68             ans+=f[i][j];
    69             if(ans>=mod)ans-=mod;
    70             if(!j)break;
    71         }
    72     }
    73     printf("%d
    ",ans);
    74 }
    View Code
  • 相关阅读:
    linux服务器网络配置
    全面了解linux服务器
    centos selinux学习记录
    centos7使用samba共享文件
    centos7修改yum下载源为阿里源
    ubuntu14.04使用samba共享文件
    计算两个经纬度之间的距离(python算法)
    awk中的冒泡排序
    linux awk时间计算脚本
    linux shell中FS、OFS、RS、ORS图解
  • 原文地址:https://www.cnblogs.com/xuruifan/p/5577328.html
Copyright © 2020-2023  润新知