[Sdoi2017]序列计数

4818: [Sdoi2017]序列计数

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 317  Solved: 210

Description

Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数。Alice还希望

,这n个数中,至少有一个数是质数。Alice想知道,有多少个序列满足她的要求。

Input

一行三个数,n,m,p。

1<=n<=10^9,1<=m<=2×10^7,1<=p<=100

Output

一行一个数,满足Alice的要求的序列数量,答案对20170408取模。

Sample Input

3 5 3

Sample Output

33

pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

先是容斥,总答案=所有的方案数-只有合数的方案数。
可以推出暴力的DP方程:
f[i][j]代表长度为i,mod
p为j的方案数
f[i][(j+k)%p]+=f[i-1][j]。
然后这样的复杂度是O(n*m*p),20分。
考虑优化,发现对于每个i的转移都是一样的,所以可以用矩阵快速幂。
设A为转移矩阵,发现每一个j都可以转移到j+k这个位置,A[j][j+k]+1。
这样暴力构矩阵复杂度为O(m*p),80分。
还可以优化,发现有很多地方可以记忆化,所以可以先预处理出1-m每个数中
p的每个剩余系的数量,然后直接加进去即可。
复杂度O(m)。100分。
 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #define maxn 20000010
 8 #define mod 20170408
 9 #define LL long long
10 using namespace std;
11 LL a[110][110][2],b[110][110][2],s[110][110];
12 int su[maxn/10],he[maxn],s1[110],s2[110];
13 LL n,m,p;
14 bool bj[maxn];
15 void mul(int a1,int b1){
16   for(int i=0;i<p;i++)
17     for(int j=0;j<p;j++)
18       for(int k=0;k<p;k++)
19     s[i][j]+=a[i][k][a1]*a[k][j][b1],s[i][j]%=mod;
20   for(int i=0;i<p;i++)
21     for(int j=0;j<p;j++)
22       a[i][j][a1]=s[i][j],s[i][j]=0;
23 }
24 void mul1(int a1,int b1){
25   for(int i=0;i<p;i++)
26     for(int j=0;j<p;j++)
27       for(int k=0;k<p;k++)
28     s[i][j]+=b[i][k][a1]*b[k][j][b1],s[i][j]%=mod;
29   for(int i=0;i<p;i++)
30     for(int j=0;j<p;j++)
31       b[i][j][a1]=s[i][j],s[i][j]=0;
32 }
33 int main()
34 {
35   freopen("count.in","r",stdin);
36   freopen("count.out","w",stdout);
37   LL tot=0,tot1=0;
38   scanf("%lld%lld%lld",&n,&m,&p);
39   for(int i=1;i<=m;i++) a[0][i%p][0]++;
40   for(int i=1;i<=m;i++) s1[i%p]++;
41   for(int i=0;i<p;i++)
42     for(int j=0;j<p;j++)
43       a[j][(j+i)%p][1]+=s1[i];
44   int mi=n-1;
45   while(mi){
46     if(mi%2) mul(0,1);
47     mi>>=1;
48     mul(1,1);
49   }
50   bj[1]=1;
51   for(int i=2;i<=m;i++){
52     if(!bj[i]) su[++tot]=i;
53     for(int j=1;j<=tot;j++){
54       if(su[j]*i>m) break;
55       bj[su[j]*i]=1;
56       if(i%su[j]==0) break;
57     }
58   }
59   for(int i=1;i<=m;i++) if(bj[i])b[0][i%p][0]++;
60   for(int i=1;i<=m;i++) if(bj[i])s2[i%p]++;
61   for(int i=0;i<p;i++)
62     for(int j=0;j<p;j++)
63       b[j][(j+i)%p][1]+=s2[i];
64   mi=n-1;
65   while(mi){
66     if(mi%2) mul1(0,1);
67     mi>>=1;
68     mul1(1,1);
69   }
70   printf("%lld",(a[0][0][0]-b[0][0][0]+mod)%mod);
71   return 0;
72 }

				
时间: 2024-11-05 13:48:15

[Sdoi2017]序列计数的相关文章

【BZOJ4818】[Sdoi2017]序列计数 DP+矩阵乘法

[BZOJ4818][Sdoi2017]序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求. Input 一行三个数,n,m,p. 1<=n<=10^9,1<=m<=2×10^7,1<=p<=100 Output 一行一个数,满足Alice的要求的序列数量,答案对20170408取模. Sampl

P3702 [SDOI2017]序列计数

P3702 [SDOI2017]序列计数 链接 分析: 代码: #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map

[bzoj4818][Sdoi2017]序列计数_矩阵乘法_欧拉筛

[Sdoi2017]序列计数 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=4818. 题解: 首先列出来一个递推式子 $f[i][0]$表示$i$个任意数的答案. $f[i][1]$表示$i$个合数的答案. 转移的时候发现可以用矩阵优化这个过程. 至于怎么把矩阵建出来,我们可以开个桶来解决这个问题. 代码: #include <bits/stdc++.h> using namespace std; typedef long lon

【bzoj4818】 Sdoi2017—序列计数

http://www.lydsy.com/JudgeOnline/problem.php?id=4818 (题目链接) 题意 一个长度为$n$的序列,每个元素是不超过$m$的正整数,且这$n$个数的和是$p$的倍数,这$n$个数中至少有一个是质数,问这样的序列有多少个. Solution md吓死我了,还以为想错了,$p^2\log n$的半天不敢写=.= $f[i][j]$表示忽略质数条件下的长度为$i$,和$mod~p=j$的序列数:$g[i][j]$表示满足没有一个数是质数的情况下长度为$

[bzoj4818][Sdoi2017]序列计数

来自FallDream,未经允许,请勿转载,谢谢.  Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求.答案取模20170408 n<=10^9 m<=2*10^7 p<=100 题解:考虑计算任意选择的答案 然后把质数去掉,再算一次答案,求差即可. 然后这道题数据范围好水啊 p只有100  瞎矩阵乘法都能过 那个要k^3logn 当然,直接生成函

【bzoj4818】[Sdoi2017]序列计数 矩阵乘法

原文地址:http://www.cnblogs.com/GXZlegend/p/6825132.html 题目描述 Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求. 输入 一行三个数,n,m,p. 1<=n<=10^9,1<=m<=2×10^7,1<=p<=100 输出 一行一个数,满足Alice的要求的序列数量,答案对2017

BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法

Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求. Input 一行三个数,n,m,p. 1<=n<=10^9,1<=m<=2×10^7,1<=p<=100 Output 一行一个数,满足Alice的要求的序列数量,答案对20170408取模. Sample Input 3 5 3 Sample Outp

BZOJ 4818 SDOI2017 序列计数

刚出炉的省选题,还是山东的. 自古山东出数学和网络流,堪称思维的殿堂,比某地数据结构成风好多了. 废话不说上题解. 1.题面 求:n个数(顺序可更改),值域为[1,m],和为p的倍数,且这些树里面有质数的方案数是多少? 解题报告: 0% O(n^n)爆搜,没什么好讲的,用来拍DP: #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #define LL

codevs 5964 [SDOI2017]序列计数

 [题解] 官方题解就两句话. 写了三个版本的不同分值代码.看代码吧. 前导1 //f[i][j][1/0]表示长为i,sum mod p=j,是否已经选了质数的方案数 #include<cstdio> using namespace std; const int mod=20170408; const int N=1e6+1; int tot,prime[N/3];bool check[N]; int n,m,f[2][N][2];int p; void pre(){ n=1e6;check