zoukankan      html  css  js  c++  java
  • [NOI2005]寿司晚宴

    题目描述

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

    在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1,其中第种寿司的美味度为i+1(即寿司的美味度为从2到n)。

    现在小G和小W希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小G品尝的寿司种类中存在一种美味度为x的寿司,小W品尝的寿司中存在一种美味度为y的寿司,而x与y不互质。

    现在小G和小W希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数p取模)。注意一个人可以不吃任何寿司。

    输入输出格式

    输入格式:

    从文件dinner.in中读入数据。

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

    输出格式:

    输出到文件dinner.out中。

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

    输入输出样例

    输入样例#1:
    3 10000
    输出样例#1:
    9
    输入样例#2:
    4 10000
    输出样例#2:
    21
    输入样例#3:
    100 100000000
    输出样例#3:
    3107203
    题解:
    小于√500的素数有8个,对于题意,可以理解为两人不能有同一素数倍数的寿司
    比如选了6,相当于选了2,3,则;另一人不能选2,3的倍数
    用8为二进制数来保存情况,状压dp
    f[j][k]表示小G为j小W为k的方案数,p[1][j][k]表示小G选,p[2][j][k]表示小w选
    注意一个数可能有大于√500的因数,但显然只能有一个,记录下为ki,如果ki相同也不能选
    转移后f[j][k]=p[1][j][k]+p[2][j][k]-f[j][k]
    减去f[j][k]是因为p[1],p[2]都算了f[j][k],所以减去
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 struct Node
     7 {
     8     int se,ki;
     9 } s[1201];
    10 int prime[8]= {2,3,5,7,11,13,17,19};
    11 int n;
    12 int p[3][601][601],f[601][601],Mod,ans;
    13 bool cmp(Node a,Node b)
    14 {
    15     if (a.ki!=b.ki) return a.ki<b.ki;
    16     else return a.se<b.se;
    17 }
    18 int main()
    19 {int i,j,k;
    20     //freopen("1.out","w",stdout);
    21     cin>>n>>Mod;
    22     for (int i=1; i<=n; i++)
    23     {
    24         int tmp;
    25         tmp=i;
    26         //cout<<i<<endl;
    27         for (int j=0; j<8; j++)
    28         {
    29             if (tmp%prime[j]==0)
    30             {
    31                 s[i].se|=1<<j;
    32                 while (tmp%prime[j]==0) tmp/=prime[j];
    33             }
    34         }
    35         s[i].ki=tmp;
    36     }
    37     sort(s+2,s+n+1,cmp);
    38     f[0][0]=1;
    39     for (int i=2; i<=n; i++)
    40     {
    41         if (i==2||s[i].ki==1||s[i].ki!=s[i-1].ki)
    42         {
    43             for (int j=0; j<=255; j++)
    44             {
    45                 for (int k=0; k<=255; k++)
    46                 {
    47                 p[1][j][k]=f[j][k];
    48                 p[2][j][k]=f[j][k];
    49                 }
    50             }
    51         }
    52         for (int j=255; j>=0; j--)
    53         {
    54             for (int k=255; k>=0; k--)
    55             {
    56                 if ((k&s[i].se)==0) p[1][j|s[i].se][k]=(p[1][j|s[i].se][k]+p[1][j][k])%Mod;
    57                  if ((j&s[i].se)==0) p[2][j][k|s[i].se]=(p[2][j][k|s[i].se]+p[2][j][k])%Mod;
    58             }
    59         }
    60         if (i==n||s[i].ki==1||s[i].ki!=s[i+1].ki)
    61         {
    62             for (int j=0; j<=255; j++)
    63             {
    64                 for (int k=0; k<=255; k++)
    65                 {
    66                     f[j][k]=((p[1][j][k]+p[2][j][k]-f[j][k])%Mod+Mod)%Mod;
    67                 }
    68             }
    69         }
    70     }
    71     for (int i=0; i<=255; i++)
    72     {
    73         for (int j=0; j<=255; j++)
    74         {
    75             if ((i&j)==0)
    76             {
    77             //printf("%d %d %d
    ",f[i][j],i,j);
    78                     ans=(ans+f[i][j])%Mod;
    79             }
    80         }
    81     }
    82     cout<<ans;
    83 }
  • 相关阅读:
    BootStrap 学习笔记一
    ROW_NUMBER() OVER的用法
    Angularjs学习笔记(五)----显示和格式化数据
    &&和||的妙用
    形象的讲解angular中的$q与promise(转)
    Angularjs学习笔记(四)----与后端服务器通信
    Angularjs学习笔记(一)
    Angularjs学习笔记(二)----模块
    Angularjs学习笔记(三)----依赖注入
    StringBuilder类型
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7204037.html
Copyright © 2011-2022 走看看