感觉自己的复杂度感人

大概是\(O(p*\pi(m)+p^3logn)\)

还是能过去的

我们看到这么大的数据范围还是应该先想一想暴力怎么写

显然我们可以直接暴力\(dp\)

设\(dp[i][j]\)表示已经选择了\(i\)数,其中所有数的和\(mod\ p\)为\(j\)的方案数

显然方程是

\[f[i][j]=\sum_{k=1}^mdp[i-1][((j-k)\%p+p)\%p]
\]

初始的状态是\(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]序列计数】的更多相关文章

  1. [Sdoi2017]序列计数 [矩阵快速幂]

    [Sdoi2017]序列计数 题意:长为\(n \le 10^9\)由不超过\(m \le 2 \cdot 10^7\)的正整数构成的和为\(t\le 100\)的倍数且至少有一个质数的序列个数 总- ...

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

    BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ...

  3. 【BZOJ 4818】 4818: [Sdoi2017]序列计数 (矩阵乘法、容斥计数)

    4818: [Sdoi2017]序列计数 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 560  Solved: 359 Description Al ...

  4. P3702 [SDOI2017]序列计数

    P3702 [SDOI2017]序列计数 链接 分析: 首先可以容斥掉,用总的减去一个质数也没有的. 然后可以dp了,f[i][j]表示到第i个数,和在模p下是j的方案数,矩阵快速幂即可. 另一种方法 ...

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

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

  6. BZOJ4818 LOJ2002 SDOI2017 序列计数 【矩阵快速幂优化DP】*

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

  7. [BZOJ4818][SDOI2017]序列计数(动规+快速幂)

    4818: [Sdoi2017]序列计数 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 972  Solved: 581[Submit][Status ...

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

    [Sdoi2017]序列计数 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=4818. 题解: 首先列出来一个递推式子 $f[i][0]$ ...

  9. [BZOJ 4818/LuoguP3702][SDOI2017] 序列计数 (矩阵加速DP)

    题面: 传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4818 Solution 看到这道题,我们不妨先考虑一下20分怎么搞 想到暴力,本蒟 ...

  10. bzoj4818 [Sdoi2017]序列计数

    Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望,这n个数中,至少有一个数是质数.Alice想知道,有多少个序 ...

随机推荐

  1. 关于容器、虚拟机以及 Docker 的一个入门教程

    Yves yao · 2017-09-05翻译 · 1315阅读 原文链接 huangxiaolu审校   源地址:http://zcfy.cc/article/a-beginner-friendly ...

  2. Freebsd10.3(FreeBSD11 Beta1)使用手记

    Freebsd10.3(FreeBSD11 Beta1)使用手记 1.安装系统. 2.设置ssh2登录,并开启ftp. (1)编辑/etc/ssh/sshd_config文件,设置如下: Permit ...

  3. Django——REST framework

    1. 什么是REST REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角度类审 ...

  4. HTML中的Head标签学习

    在页面加载完成的时候,标签head里的内容,是不会在页面中显示出来的.它包含了像页面的<title>(标题) ,CSS(如果你想用CSS来美化页面内容),图标和其他的元数据(比如 作者,关 ...

  5. Google APAC----Africa 2010, Qualification Round(Problem B. Reverse Words)----Perl 解法

    原题地址链接:https://code.google.com/codejam/contest/351101/dashboard#s=p1 问题描述: Problem Given a list of s ...

  6. [转] Linux 3.10 ARM Device Tree 的初始化

    [转] Linux 3.10 ARM Device Tree 的初始化 本文代码均来自标准 linux kernel 3.10,可以到这里下载 https://www.kernel.org/     ...

  7. 前端构建工具Gulp的学习和使用

    前几天刚鼓捣了Grunt的使用,结果文档还没捂热,老大说我们还是用gulp吧,搞得我又得来整gulp,眼泪流成河了,真是不晓得底层人民的辛苦啊.不过经过对gulp的学习,发现很好用,比grunt舒服! ...

  8. Vue实例对象的数据选项(火柴)

    前言 一般地,当模板内容比较简单的时候,使用data选项配合表达式即可.涉及到复杂逻辑时,则需要用到methods.computed.watch等方法.本文将详细介绍Vue实例对象的数据选项. dat ...

  9. qss 对子控件的设置样式 使用setProperty --Qt 之 QSS(动态属性)

    https://blog.csdn.net/liang19890820/article/details/51693956 学习了 代码: 当鼠标划过控件时,设置样式 void CustomLabelW ...

  10. 第十五章——自编码器(Autoencoders)

    自编码器是一种能够通过无监督学习,学到输入数据高效表示的人工神经网络.输入数据的这一高效表示称为编码(codings),其维度一般远小于输入数据,使得自编码器可用于降维(查看第八章).更重要的是,自编 ...