【[SDOI2017]序列计数】
感觉自己的复杂度感人
大概是\(O(p*\pi(m)+p^3logn)\)
还是能过去的
我们看到这么大的数据范围还是应该先想一想暴力怎么写
显然我们可以直接暴力\(dp\)
设\(dp[i][j]\)表示已经选择了\(i\)数,其中所有数的和\(mod\ p\)为\(j\)的方案数
显然方程是
\]
初始的状态是\(dp[0][0]=1\),最终的答案是\(dp[n][0]\)
至于还有一个至少有一个素数的限制条件,我们可以先不管这个条件直接算一遍,之后再保证\(k\)不为素数再算一遍,两个一减就是答案了
这样暴力转移的复杂度是\(O(nmp)\)的,于是我们要考虑优化
这个转移相当的固定,于是可以矩乘优化
我们发现因为\(p\)非常的小,于是那个膜\(p\)意义下的转移会有很多重复的位置被转移过去,于是我们如果可以预处理出这样一个数组\(tot[j][k]\)
表示\(dp[i-1][k]\)会向\(dp[i][k]\)专一多少次,也就是\(dp[i][k]+=dp[i-1][j]*tot[j][k]\)
于是就有这样一个矩阵会被构造出来
(\(p=3\)的情况)
于是就可以转移了,至于\(tot[j][k]\)怎么求,这个就是很简单了
在没有素数的情况下把所有素数对应的转移减一遍就好了
代码
#include<iostream>
#include<cstring>
#include<bitset>
#include<cstdio>
#define re register
#define maxn 20000005
#define LL long long
const LL mod=20170408;
std::bitset<maxn> f;
int prime[1500000];
LL ans[101][101],a[101][101];
int m,p;
LL n;
inline void did_a()
{
LL mid[101][101];
for(re int i=1;i<=p;i++)
for(re int j=1;j<=p;j++)
mid[i][j]=a[i][j],a[i][j]=0;
for(re int i=1;i<=p;i++)
for(re int j=1;j<=p;j++)
for(re int k=1;k<=p;k++)
a[i][j]=(a[i][j]+(mid[i][k]*mid[k][j])%mod)%mod;
}
inline void did_ans()
{
LL mid[101][101];
for(re int i=1;i<=p;i++)
for(re int j=1;j<=p;j++)
mid[i][j]=ans[i][j],ans[i][j]=0;
for(re int i=1;i<=p;i++)
for(re int j=1;j<=p;j++)
for(re int k=1;k<=p;k++)
ans[i][j]=(ans[i][j]+(mid[i][k]*a[k][j])%mod)%mod;
}
inline void Rebuild()
{
memset(ans,0,sizeof(ans));
memset(a,0,sizeof(a));
for(re int i=1;i<=p;i++)
ans[i][i]=1;
int t=m/p;
for(re int i=1;i<=p;i++)
for(re int j=1;j<=p;j++)
a[i][j]=t;
int tot=m%p;
for(re int i=1;i<=p;i++)
{
int cnt=tot,x=i-1;
if(!x) x=p;
while(cnt)
{
a[i][x]++,cnt--;
x--;
if(!x) x=p;
}
}
}
inline void out()
{
for(re int i=1;i<=p;i++)
{
for(re int j=1;j<=p;j++)
printf("%d ",a[i][j]);
putchar(10);
}
}
inline void quick(LL b)
{
while(b)
{
if(b&1ll) did_ans();
b>>=1ll;
did_a();
}
}
int main()
{
scanf("%lld%d%d",&n,&m,&p);
f[1]=1;
for(re int i=2;i<=m;i++)
{
if(!f[i]) prime[++prime[0]]=i;
for(re int j=1;j<=prime[0]&&prime[j]*i<=m;j++)
{
f[prime[j]*i]=i;
if(i%prime[j]==0) break;
}
}
Rebuild();
quick(n);
LL num=ans[1][1];
Rebuild();
for(re int i=1;i<=p;i++)
{
for(re int j=1;j<=prime[0];j++)
{
a[i][((i-1-prime[j])%p+p)%p+1]--;
if(a[i][(i-prime[j]+p)%p+1]<0) a[i][(i-prime[j]+p)%p+1]=mod-1;
}
}
quick(n);
std::cout<<(num-ans[1][1]+mod)%mod;
return 0;
}
【[SDOI2017]序列计数】的更多相关文章
- [Sdoi2017]序列计数 [矩阵快速幂]
[Sdoi2017]序列计数 题意:长为\(n \le 10^9\)由不超过\(m \le 2 \cdot 10^7\)的正整数构成的和为\(t\le 100\)的倍数且至少有一个质数的序列个数 总- ...
- BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法
BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ...
- 【BZOJ 4818】 4818: [Sdoi2017]序列计数 (矩阵乘法、容斥计数)
4818: [Sdoi2017]序列计数 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 560 Solved: 359 Description Al ...
- P3702 [SDOI2017]序列计数
P3702 [SDOI2017]序列计数 链接 分析: 首先可以容斥掉,用总的减去一个质数也没有的. 然后可以dp了,f[i][j]表示到第i个数,和在模p下是j的方案数,矩阵快速幂即可. 另一种方法 ...
- 【BZOJ4818】[Sdoi2017]序列计数 DP+矩阵乘法
[BZOJ4818][Sdoi2017]序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数 ...
- BZOJ4818 LOJ2002 SDOI2017 序列计数 【矩阵快速幂优化DP】*
BZOJ4818 LOJ2002 SDOI2017 序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数. Alice还希 ...
- [BZOJ4818][SDOI2017]序列计数(动规+快速幂)
4818: [Sdoi2017]序列计数 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 972 Solved: 581[Submit][Status ...
- [bzoj4818][Sdoi2017]序列计数_矩阵乘法_欧拉筛
[Sdoi2017]序列计数 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=4818. 题解: 首先列出来一个递推式子 $f[i][0]$ ...
- [BZOJ 4818/LuoguP3702][SDOI2017] 序列计数 (矩阵加速DP)
题面: 传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4818 Solution 看到这道题,我们不妨先考虑一下20分怎么搞 想到暴力,本蒟 ...
- bzoj4818 [Sdoi2017]序列计数
Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望,这n个数中,至少有一个数是质数.Alice想知道,有多少个序 ...
随机推荐
- python学习之老男孩python全栈第九期_day026知识点总结——封装、property、类方法、初识反射
一. 封装 class Room: def __init__(self, name, length, width): self.__name = name self.__length = length ...
- JavaScript周报#183
This week’s JavaScript news Read this issue on the Web | Issue Archive JavaScript Weekly Issue 183Ma ...
- 理解webpack4.splitChunks
一.前言 之前一直也没有研究过webpack4是基于怎样的规则去拆分模块的,现在正好有时间打算好好了解一下,看了官方文档也陆陆续续的看了看网上别人写的文章,感觉大部分都是将官方文档翻译了一遍,很多问题 ...
- 最齐全的vue公共函数给你们放出来啦
import Vue from 'vue' /* 配置参数 */Vue.prototype.winH = document.documentElement.clientHeight; Vue.prot ...
- java三元运算符
由?:符号表示的,具体的含义其实就和if-else结构的含义差不多,这种运算符会将某个条件作两种处理,如果满足条件的话就执行第一个结果,如果不满足的话就执行另外一个结果,例如: Int A,B,C; ...
- Sass、Less、Stylus,我选Sass!
Sass官网 | Sass中文 简介:待添加 Less 简介:待添加 Stylus 简介:待添加
- Spring与Web整合
一 概述 1.整合目的 将所有对象的创建与管理任务交给Spring容器,降低程序的耦合度. 2.整合途径 将Spring容器注入到Web容器中. 3.具体实现 使用ServletContextList ...
- 关于 webpack 跨域
一.使用 http-proxy-middleware 代理 安装 http-proxy-middleware 依赖 在src 目录下 新建一个 setupProxy.js文件 // 引用依赖 va ...
- MySQL数据库(11)----使用子查询实现多表查询
子查询指的是用括号括起来,并嵌入另一条语句里的那条 SELECT 语句.下面有一个示例,它实现的是找出与考试类别('T')相对应的所有考试事件行的 ID,然后利用它们来查找那些考试的成绩: SELEC ...
- docker pull提示x509错误的对应方法
在一台虚拟机上使用docker pull时出现了x509错误,相关原因与对应方法简单memo如下. 错误现象 在使用docker pull从dockerhub上下载镜像时提示如下错误 docker: ...