AC日记——「SDOI2017」序列计数 LibreOJ 2002

「SDOI2017」序列计数

思路:

  矩阵快速幂;

代码:

#include <bits/stdc++.h>
using namespace std;
#define mod 20170408
#define ll long long
struct MatrixType {
    int n,m;
    ll ai[105][105];
    void mem(int n_,int m_)
    {
        n=n_,m=m_;
        for(int i=0;i<=n;i++) for(int v=0;v<=m;v++) ai[i][v]=0;
    }
    MatrixType operator*(const MatrixType pos)const
    {
        MatrixType res;res.mem(this->n,pos.m);
        for(int i=0;i<=res.n;i++)
            for(int v=0;v<=res.m;v++)
                for(int x=0;x<=this->m;x++)
                    res.ai[i][v]=(res.ai[i][v]+(this->ai[i][x]*pos.ai[x][v])%mod)%mod;
        return res;
    }
    void debug()
    {
        puts("");
        printf("%d %d\n",n,m);
        for(int i=0;i<=2;i++)
        {
            for(int v=0;v<=2;v++) printf("%d ",this->ai[i][v]);
            putchar(‘\n‘);
        }
        puts("");
    }
};
int n,m,p,pi[2000005],cnt,ai[1001],bi[1001];
bool if_p[20000005];
MatrixType poww(MatrixType pos,int mi)
{
    MatrixType res=pos;mi--;
    while(mi)
    {
        if(mi&1) res=res*pos;
        mi=mi>>1,pos=pos*pos;
    }
    return res;
}
void ouler(int lit)
{
    for(int i=2;i<=lit;i++)
    {
        if(!if_p[i]) pi[++cnt]=i;
        for(int j=1;pi[j]*i<=lit&&j<=cnt;j++)
        {
            if_p[i*pi[j]]=true;
            if(i%pi[j]==0) break;
        }
    }
}
int main()
{
    //freopen("ans3.txt","w",stdout);
    scanf("%d%d%d",&n,&m,&p),ouler(m);
    MatrixType sta1;sta1.mem(0,p-1);
    sta1.ai[0][0]=1;
    MatrixType pos1,pos2,ans1,ans2;
    pos1.mem(p-1,p-1),pos2.mem(p-1,p-1);
    for(int i=1;i<=m;i++) ai[i%p]++;
    for(int i=0;i<p;i++) bi[i]=ai[i];
    for(int i=1;i<=cnt;i++) bi[pi[i]%p]--;
    for(int i=0;i<p;i++)
    {
        for(int v=0;v<p;v++)
        {
            if(i>v) pos1.ai[i][v]=ai[i-v],pos2.ai[i][v]=bi[i-v];
            if(i==v) pos1.ai[i][v]=ai[0],pos2.ai[i][v]=bi[0];
            if(i<v) pos1.ai[i][v]=ai[p-v+i],pos2.ai[i][v]=bi[p-v+i];
        }
    }
    pos1=poww(pos1,n),pos2=poww(pos2,n);
    ans1=sta1*pos1,ans2=sta1*pos2;
    cout<<(ans1.ai[0][0]-ans2.ai[0][0]+mod)%mod;
    return 0;
}
时间: 2024-10-05 05:52:32

AC日记——「SDOI2017」序列计数 LibreOJ 2002的相关文章

LibreOJ #2002. 「SDOI2017」序列计数

二次联通门 : LibreOJ #2002. 「SDOI2017」序列计数 /* LibreOJ #2002. 「SDOI2017」序列计数 线性筛 + 矩阵优化dp 先构造出全部情况的矩阵 用矩阵快速幂计算答案 再构造出全不是质数的矩阵 计算出答案 前一个答案减后一个答案即可 */ #include <cstdio> #include <iostream> #include <cstring> const int BUF = 12312312; char Buf[BU

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]

AC日记——「SCOI2016」背单词 LiBreOJ 2012

#2012. 「SCOI2016」背单词 思路: Orz: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxm 510005 int n,ch[maxm][26],tot=1,len,head[maxm],E[maxm],V[maxm],cnt=1; int val[maxm],cnt2,size[maxm],sta[maxm],top; long long ans,sum; ch

AC日记——「SCOI2015」国旗计划 LiBreOJ 2007

#2007. 「SCOI2015」国旗计划 思路: 跪烂Claris 代码: #include <cstdio> #include <algorithm> #define maxn 800010 int n,m,ai[maxn][2],bi[maxn],f[maxn<<1],st[maxn]; int g[maxn],nxt[maxn<<1],q[maxn<<1],t,ans[maxn],L,x,y,i; inline void in(int&a

loj#2002. 「SDOI2017」序列计数(dp 矩阵乘法)

题意 题目链接 Sol 质数的限制并没有什么卵用,直接容斥一下:答案 = 忽略质数总的方案 - 没有质数的方案 那么直接dp,设\(f[i][j]\)表示到第i个位置,当前和为j的方案数 \(f[i + 1][(j + k) \% p] += f[i][j]\) 矩乘优化一下. #include<bits/stdc++.h> #define LL long long using namespace std; const int MAXN = 2e7 + 10, mod = 20170408,

AC日记——「SCOI2015」情报传递 LiBreOJ 2011

#2011. 「SCOI2015」情报传递 思路: 可持久化树状数组模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define maxm maxn*100 int deep[maxn],f[maxn],id[maxn],top[maxn],cnt,soot; int head[maxn],V[maxn],E[maxn],lar[maxn],size[maxn]; int val[maxm],

loj2004. 「SDOI2017」硬币游戏

2004. 「SDOI2017」硬币游戏 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利. 大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了. 同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况. 用 $ \texttt{H} $ 表示正面朝上, 用 $ \texttt{T} $ 表示反面朝上,扔很多次硬币后,会得到一个硬币序列.比如 $ \texttt{HTT} $ 表示第一次正面朝上,后两次反面朝上. 但扔到什么时

「JSOI2014」序列维护

「JSOI2014」序列维护 传送门 其实这题就是luogu的模板线段树2,之所以要发题解就是因为被 \(\color{black}{\text{M}} \color{red}{\text{_sea}}\) 告知了一种比较NB的 \(\text{update}\) 的方式. 我们可以把修改操作统一化,视为 \(ax + b\) 的形式,然后我们按照原来的套路来维护两个标记,分别代表 \(a\) 和 \(b\) ,那么我们的更新就可以这么写: inline void f(int p, int at

「LuoguP1430」 序列取数

题目描述 给定一个长为n的整数序列(n<=1000),由A和B轮流取数(A先取).每个人可从序列的左端或右端取若干个数(至少一个),但不能两端都取.所有数都被取走后,两人分别统计所取数的和作为各自的得分.假设A和B都足够聪明,都使自己得分尽量高,求A的最终得分. 输入输出格式 输入格式: 第一行,一个正整数T,表示有T组数据.(T<=100) 接着T行,每行第一个数为n,接着n个整数表示给定的序列. 输出格式: 输出T行,每行一个整数,表示A的得分 输入输出样例 输入样例#1: 复制 2 1