[SDOI2017]序列计数
2024-10-19 06:21:33
题目描述
Alice想要得到一个长度为nn的序列,序列中的数都是不超过mm的正整数,而且这nn个数的和是pp的倍数。
Alice还希望,这nn个数中,至少有一个数是质数。
Alice想知道,有多少个序列满足她的要求。
输入输出格式
输入格式:
一行三个数,n,m,pn,m,p。
输出格式:
一行一个数,满足Alice的要求的序列数量,答案对2017040820170408取模。
输入输出样例
说明
对20\%20%的数据,1\leq n,m\leq1001≤n,m≤100
对50\%50%的数据,1\leq m \leq 1001≤m≤100
对80\%80%的数据,1\leq m\leq 10^61≤m≤106
对100\%100%的数据,1\leq n \leq 10^9,1\leq m \leq 2\times 10^7,1\leq p\leq 1001≤n≤109,1≤m≤2×107,1≤p≤100
时间限制:3s
空间限制:128MB
至少有一个素数的方案=所有方案-没有素数的方案
于是用容斥就变成了简单的dp,先讨论所有方案
令f[i][j]表示i个数,和%p为j的方案数
f[i][j]=∑f[i-1][(j-k+p)%p]*cnt[k]
cnt[k]是1~m中%p等于k的数量
发现显然上式可以写为矩阵
于是用矩阵快速幂就行
然后用欧拉筛把素数筛掉,再做一次
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long lol;
struct Matrix
{
lol a[][];
}pre,ans1,ans2,Mat1,Mat2;
lol n,m,p,Mod=;
long long cnt1[],cnt2[];
lol tot,pri[];
bool vis[];
Matrix operator*(const Matrix a,const Matrix b)
{
lol i,j,k;
Matrix res;
memset(res.a,,sizeof(res.a));
for (k=;k<p;k++)
for (i=;i<p;i++)
if (a.a[i][k])
{
for (j=;j<p;j++)
{
res.a[i][j]+=a.a[i][k]*b.a[k][j];
res.a[i][j]%=Mod;
}
}
return res;
}
Matrix qpow1(lol y)
{lol i;
Matrix res;
memset(res.a,,sizeof(res.a));
for (i=;i<p;i++)
res.a[i][i]=;
while (y)
{
if (y&) res=res*Mat1;
Mat1=Mat1*Mat1;
y=y/;
}
return res;
}
Matrix qpow2(lol y)
{lol i;
Matrix res;
memset(res.a,,sizeof(res.a));
for (i=;i<p;i++)
res.a[i][i]=;
while (y)
{
if (y&) res=res*Mat2;
Mat2=Mat2*Mat2;
y=y/;
}
return res;
}
int main()
{lol i,j;
cin>>n>>m>>p;
cnt1[]++;
for (i=;i<=m;i++)
{
cnt1[i%p]++,cnt1[i%p]%=Mod;
if (vis[i]==)
{
++tot;
pri[tot]=i;
}
for (j=;j<=tot;j++)
{
if (i*pri[j]>m) break;
vis[i*pri[j]]=;
if (i%pri[j]==) break;
}
}
cnt2[]++;
for(i=;i<=m;i++)
if (vis[i]) cnt2[i%p]++,cnt2[i%p]%=Mod;
for (i=;i<p;i++)
{
for (j=;j<p;j++)
{
Mat1.a[i][(i+j)%p]+=cnt1[j]%Mod;
Mat1.a[i][(i+j)%p]%=Mod;
}
}
for (i=;i<p;i++)
pre.a[][i]=cnt1[i];
ans1=qpow1(n-);
ans1=pre*ans1;
for (i=;i<p;i++)
{
for (j=;j<p;j++)
{
Mat2.a[i][(i+j)%p]+=cnt2[j]%Mod;
Mat2.a[i][(i+j)%p]%=Mod;
}
}
for (i=;i<p;i++)
pre.a[][i]=cnt2[i];
ans2=qpow2(n-);
ans2=pre*ans2;
cout<<(ans1.a[][]-ans2.a[][]+Mod)%Mod;
}
最新文章
- 将WordPress安装在网站子目录的相关问题
- JavaScript == 、!=、===、!===的比较
- Apkplug 开发常见问题解答
- 脚本tips
- (2015年郑州轻工业学院ACM校赛题)H 五子棋
- MySQL Server 5.0 下载与 安装指南[图文] (安装到非系统路径+设置root账号相应password)
- MySQL数据备份之mysqldump使用(转)
- 【模板】最近公共祖先(LCA)
- C#正则表达式。
- C - Building Fence
- sql server 数据库学习
- Flask系列之自定义中间件
- C++ lower_bound 和upper_bound
- springmvc 数据验证 hibernate-validator --->;对象验证
- (function($){})(jQuery)---Javascript的神级特性:闭包
- ESXI 5.5卡在LSI_MR3.V00
- Eclipse 常用插件地址大全
- 实践作业4:Web测试实践(小组作业)每日任务记录4
- laravel上传到七牛图片插件
- 【Web crawler】print_all_links