[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\n",ans);
74 }
View Code

 

转载于:https://www.cnblogs.com/xuruifan/p/5577328.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值