BZOJ 4818

感觉不难。

首先转化一下题目,“至少有一个质数”$=$“全部方案”$ - $“一个质数也没有”。

注意到$m \leq 2e7$,$[1, m]$内的质数可以直接筛出来。

设$f_{i, j}$表示当前长度序列为$i$,当前和模$p$的值是$j$的方案数,直接无脑枚举$m$转移复杂度是$O(nmp)$的,但是发现每一次转移形式都是相同的。

$$f_{i, x} = \sum f_{i - 1, y}(y + z \equiv x(\mod p))$$

其实在模$p$的意义下大于等于$p$的数可以直接归类到这个数模$p$这一档里面,也就是说,我们可以记一个$cnt_x$表示模$p$意义下相同的数有$x$个。

$$f_{i, (x + y) \mod p} = \sum f_{i - 1, x} \times cnt_y$$

发现这个式子的形式很像矩阵快速幂的样子,然后就把转移写成矩阵的形式快速幂一下就好了。

转移矩阵的第$(i, j)$个格子是$\sum_{(i + k) \equiv j(\mod p)}cnt_k$

时间复杂度$O(m + p^3logn)$。

咕,感觉时间刚刚好。

然而再次观察一下这个式子发现是一个卷积的形式,因此可以直接$NTT$,时间复杂度可以降到$O(m + plogplogn)$,但是在这题中$p$太小了$ + $模数不好,直接暴力卷积的时间表现应该比$NTT$要优秀。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 2e7 + ;
const int M = ;
const ll P = 20170408LL; int n, m, K, pCnt = , pri[N], cnt[M];
bool np[N]; template <typename T>
inline void inc(T &x, T y) {
x += y;
if (x >= P) x -= P;
} template <typename T>
inline void sub(T &x, T y) {
x -= y;
if (x < ) x += P;
} struct Matrix {
int tn, tm;
ll s[M][M]; inline void init() {
tn = tm = ;
memset(s, , sizeof(s));
} friend Matrix operator * (const Matrix x, const Matrix y) {
Matrix res;
res.init();
res.tn = x.tn, res.tm = y.tm;
for (int k = ; k < x.tm; k++)
for (int i = ; i < x.tn; i++)
for (int j = ; j < y.tm; j++)
inc(res.s[i][j], x.s[i][k] * y.s[k][j] % P);
return res;
} inline Matrix fpow(int y) {
Matrix x = *this, res;
res.init();
res.tn = x.tn, res.tm = x.tm;
for (int i = ; i < x.tn; i++) res.s[i][i] = ;
for (; y ; y >>= ) {
if (y & ) res = res * x;
x = x * x;
}
return res;
} inline void print() {
for (int i = ; i < tn; i++)
for (int j = ; j < tm; j++)
printf("%lld%c", s[i][j], " \n"[j == tm - ]);
printf("\n");
} } trans, ans; inline void sieve() {
np[] = ;
for (int i = ; i <= m; i++) {
if (!np[i]) pri[++pCnt] = i;
for (int j = ; j <= pCnt && pri[j] * i <= m; j++) {
np[i * pri[j]] = ;
if (i % pri[j] == ) break;
}
}
} inline ll solve1() {
memset(cnt, , sizeof(cnt));
for (int i = ; i <= m; i++) ++cnt[i % K]; trans.init();
trans.tn = trans.tm = K;
for (int i = ; i < K; i++)
for (int j = ; j < K; j++)
inc(trans.s[i][(i + j) % K], 1LL * cnt[j]);
// trans.print(); trans = trans.fpow(n); // trans.print(); ans.init();
ans.s[][] = ;
ans.tn = , ans.tm = K;
ans = ans * trans;
return ans.s[][];
} inline ll solve2() {
sieve();
memset(cnt, , sizeof(cnt));
for (int i = ; i <= m; i++)
if (np[i]) ++cnt[i % K]; /* for (int i = 0; i < K; i++)
printf("%d%c", cnt[i], " \n"[i == K - 1]); */ trans.init();
trans.tn = trans.tm = K;
for (int i = ; i < K; i++)
for (int j = ; j < K; j++)
inc(trans.s[i][(i + j) % K], 1LL * cnt[j]);
// trans.print(); trans = trans.fpow(n); // trans.print(); ans.init();
ans.s[][] = ;
ans.tn = , ans.tm = K;
ans = ans * trans;
return ans.s[][];
} int main() {
scanf("%d%d%d", &n, &m, &K);
// printf("%lld\n", solve1());
// printf("%lld\n", solve2());
printf("%lld\n", (solve1() - solve2() + P) % P);
return ;
}

Luogu 3702 [SDOI2017]序列计数的更多相关文章

  1. luogu 3702 [SDOI2017]序列计数 矩阵乘法+容斥

    现在看来这道题真的不难啊~ 正着求不好求,那就反着求:答案=总-全不是质数 这里有一个细节要特判:1不是质数,所以在算全不是质数的时候要特判1 code: #include <bits/stdc ...

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

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

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

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

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

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

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

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

  6. P3702 [SDOI2017]序列计数

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

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

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

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

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

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

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

随机推荐

  1. 关于ppt的字体(转载)

    壹文钱:教程(13)——字体篇(上) 2015-11-25 @嘉文钱 幻方秋叶PPT 前三期嘉文给大家说了颜色,想复习的童鞋,链接在此: 壹文钱:教程(10)——色色,你好! 壹文钱:教程(11)—— ...

  2. 重新学习之spring第四个程序,整合struts2+hibernate+spring

    第一步:导入三大框架的jar包(struts2.3.16.1+hibernate3.2+spring3.2.4) 第二步:编写web.xml 和struts.xml和applicationContex ...

  3. am335x_y蜂鸣器驱动

    修改文件:1.板级文件/arch/arm/mach-omap2/board-am335xevm.c static struct platform_device buzzer_device= { .na ...

  4. NOIP 2005 校门外的树

    #include<iostream> #include<cstring> using namespace std; int a[10005]; int main() { mem ...

  5. java web 程序---留言板

    思路:一个form表单,用户提交留言 一个页面显示留言内容.用到Vector来存取信息并显示 cas.jsp <body> <form action="fei.jsp&qu ...

  6. Bootstrap-CL:略缩图

    ylbtech-Bootstrap-CL:略缩图 1.返回顶部 1. Bootstrap 缩略图 本章将讲解 Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstr ...

  7. [转]VS2010 常用插件

    本文来自:http://developer.51cto.com/art/201403/432954_all.htm 虽然VS2010IDE功能已经非常强大了,但是在有些地方还是可以优化,或者说有更合适 ...

  8. ROS创建Web代理(Web proxy)给QQ使用HTTP代理

    使用Web代理可以提高网页的访问速度,因为访问的数据会存储在内存或是硬盘中,就会直接从代理服务器中读取.同时,为了提高网络访问的安全性,可以给Web代理服务器设置相应的权限,使它的安全性得到提高. 下 ...

  9. Asp.net 页面传值的方法

    ASP.NET页面传值的方法 From:Refresh-air 在面试的时候,经常会遇到这样的问题,其实我们会对其中的几种方法比较熟悉,因为项目中经常使用.但是要全面的回答ASP.NET中页面传值的方 ...

  10. 5月25日-js操作DOM遍历子节点

    一.遍历节点 遍历子节点 children();//获取节点的所有直接子类 遍历同辈节点 next(); prev(); siblings();//所有同辈元素 *find(); 从后代元素中查找匹配 ...