P3321 [SDOI2015]序列统计
思路
首先有个挺显然的DP
\]
想办法优化这个DP
这个dp也可以写成这样
\]
看着一副卷积的样子
但是是乘法,可以考虑转化乘法为加法,有两种方式,取ln或者原根
注意到m是质数,所以取原根,每层之间的转移就变成卷积了
但是这题的卷积下标是模m的,所以每次乘完都要把大于m-1的加到对应项上(i+m-1和i对应)所以好像不能直接多项式快速幂
n是\(10^9\),上个类似快速幂的倍增即可
复杂度是\(O(m \log m \log n)\)
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#define int long long
using namespace std;
const int MOD = 1004535809;
const int G = 3;
const int invG = 334845270;
const int MAXN = 140000;
namespace getG{
    int q[100000],cnt=0;
    int phi(int n){
        int ans=n;
        int m=(int)sqrt(n+0.5);
        for(int i=2;i<=m;i++){
            if(n%i==0){
                ans=ans/i*(i-1);
                while(n%i==0)
                    n/=i;
            }
        }
        if(n>1)
            ans=ans/n*(n-1);
        return ans;
    }
    int my_pow(int a,int b,int mod){
        int ans=1;
        while(b){
            if(b&1)
                ans=(1LL*ans*a)%mod;
            a=(1LL*a*a)%mod;
            b>>=1;
        }
        return ans;
    }
    int G(int m){
        int Phi = phi(m);
        int sq=sqrt(Phi),mid=Phi;
        for(int i=2;i<=sq;i++)
            if(mid%i==0){
                q[++cnt]=Phi/i;
                while(mid%i==0)
                    mid/=i;
            }
        if(mid>1)
            q[++cnt]=Phi/mid;
        for(int g=2;1;g++){
            int f=true;
            if(my_pow(g,Phi,m)!=1)
                continue;
            else
                for(int j=1;j<=cnt;j++){
                    if(my_pow(g,q[j],m)==1){
                        f=false;
                        break;
                    }
                }
            if(f)
                return g;
        }
    }
};
int rev[MAXN];
int my_pow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)
            ans=(1LL*ans*a)%MOD;
        a=(1LL*a*a)%MOD;
        b>>=1;
    }
    return ans;
}
void cal_rev(int n,int lim){
    for(int i=0;i<n;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(lim-1));
}
void NTT(int *a,int opt,int n,int lim){
    for(int i=0;i<n;i++)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int i=2;i<=n;i<<=1){
        int len=i/2;
        int tmp=my_pow((opt)?G:invG,(MOD-1)/i);
        for(int j=0;j<n;j+=i){
            int arr=1;
            for(int k=j;k<j+len;k++){
                int t=(1LL*a[k+len]*arr)%MOD;
                a[k+len]=(a[k]-t+MOD)%MOD;
                a[k]=(a[k]+t)%MOD;
                arr=(1LL*arr*tmp)%MOD;
            }
        }
    }
    if(!opt){
        int invN = my_pow(n,MOD-2);
        for(int i=0;i<n;i++)
            a[i]=(1LL*a[i]*invN)%MOD;
    }
}
void mul(int *a,int *b,int &at,int bt){
    int num=(at+bt),n=1,lim=0;
    while(n<=(num+2))
        n<<=1,lim++;
    cal_rev(n,lim);
    static int tmp[MAXN];
    for(int i=0;i<n;i++)
        tmp[i]=b[i];
    NTT(a,1,n,lim);
    NTT(tmp,1,n,lim);
    for(int i=0;i<n;i++)
        a[i]=(1LL*a[i]*tmp[i])%MOD;
    NTT(a,0,n,lim);
    at+=bt;
}
void sqr(int *a,int &at){
    int num=(at+at),n=1,lim=0;
    while(n<=(num+2))
        n<<=1,lim++;
    cal_rev(n,lim);
    static int tmp[MAXN];
    for(int i=0;i<n;i++)
        tmp[i]=a[i];
    NTT(tmp,1,n,lim);
    for(int i=0;i<n;i++)
        a[i]=(1LL*tmp[i]*tmp[i])%MOD;
    NTT(a,0,n,lim);
    at=num;
}
void my_pow(int *a,int *b,int n,int m,int k){
    static int tmp[MAXN];
    for(int i=0;i<=n;i++)
        tmp[i]=a[i];
    b[0]=1;
    int bt=m-1;
    while(k){
        if(k&1){
            mul(b,tmp,bt,n);
            for(int i=0;i<m;i++){
                b[i]=(b[i]+b[i+m-1])%MOD;
                b[i+m-1]=0;
            }
            for(int i=m;i<=bt;i++)
                b[i]=0;
            bt=m-1;
        }
        sqr(tmp,n);
        for(int i=0;i<m;i++){
            tmp[i]=(tmp[i]+tmp[i+m-1])%MOD;
            tmp[i+m-1]=0;
        }
        for(int i=m;i<=n;i++)
            tmp[i]=0;
        n=m-1;
        k>>=1;
    }
}
int n,m,pos[MAXN],S,x,a[MAXN],b[MAXN];
signed main(){
    scanf("%lld %lld %lld %lld",&n,&m,&x,&S);
    int g=getG::G(m);
    for(int i=1,t=1;i<=m-2;i++){
        t=(1LL*t*g)%m;
        pos[t]=i;
    }
    for(int i=1;i<=S;i++){
        int midx;
        scanf("%lld",&midx);
        if(midx)
            a[pos[midx]]=1;
    }
    my_pow(a,b,m-1,m,n);
    printf("%lld\n",b[pos[x]]);
    return 0;
}
												
											P3321 [SDOI2015]序列统计的更多相关文章
- P3321 [SDOI2015]序列统计 FFT+快速幂+原根
		
\(\color{#0066ff}{ 题目描述 }\) 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S.小C用这 ...
 - [洛谷P3321][SDOI2015]序列统计
		
题目大意:给你一个集合$n,m,x,S(S_i\in(0,m],m\leqslant 8000,m\in \rm{prime},n\leqslant10^9)$,求一个长度为$n$的序列$Q$,满足$ ...
 - Luogu P3321 [SDOI2015]序列统计
		
一道不错的多项式好题.还涉及了一些数论内容. 首先我们看到题目是求乘积模\(m\)的方案数,考虑到这种方案数我们一般都可以用生成函数来做. 但显然卷积的下标有加(FFT,NTT等)有位运算(FWT)但 ...
 - 洛咕 P3321 [SDOI2015]序列统计
		
显然dp就是设\(f[i][j]\)表示dp了i轮,对m取膜是j的方案数 \(f[i][xy\mod m]=f[i-1][x]\times f[i-1][y]\) 这是\(O(nm^2)\)的 像我这 ...
 - 洛谷P3321 [SDOI2015]序列统计(NTT)
		
传送门 题意:$a_i\in S$,求$\prod_{i=1}^na_i\equiv x\pmod{m}$的方案数 这题目太珂怕了……数学渣渣有点害怕……kelin大佬TQL 设$f[i][j]$表示 ...
 - BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]
		
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1017 Solved: 466[Submit][Statu ...
 - [SDOI2015]序列统计
		
[SDOI2015]序列统计 标签: NTT 快速幂 Description 给你一个模m意义下的数集,需要用这个数集生成一个数列,使得这个数列在的乘积为x. 问方案数模\(1004535809\). ...
 - 3992: [SDOI2015]序列统计
		
3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...
 - [BZOJ 3992][SDOI2015]序列统计
		
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 2275 Solved: 1090[Submit][Stat ...
 
随机推荐
- 小程序报错 TLS 版本必须大于等于 1.2
			
https://www.cnblogs.com/phpper/p/6866036.html 服务器是windows 2008 server 环境是IIS7SSL是申请用的阿里免费.微信小程序发现wx. ...
 - 于用cocoapods添加第三方库,并且cocoapods添加成功,但是却在任何一个文件上都导入不了头文件
			
关于用cocoapods添加第三方库,并且cocoapods添加成功,但是却在任何一个文件上都导入不了头文件,而且根本没有提示,即使手动打#import "xxxx.h"也报错xx ...
 - ubuntu安装zabbix 3.2(转)
			
转自:http://www.zabbix.org.cn/viewtopic.php?f=13&t=1096本人略做了写修改. 准备工作 apt-get update apt-get upgra ...
 - 关于html/css的一些小技巧之hack掉"margin-top"层叠问题
			
身为小前端菜鸟一枚,忽然听到这样一则传言~~ 心情久久不能平复,想到前几日,开通了博客君,特来此寻找存在feeling~ 旨在造福普罗大众(更多前端小菜鸟) 话不多说, 我们步入正题,今天来给大家分享 ...
 - elastic-job集成到springboot教程,和它的一个异常处理办法:Sharding item parameters '1' format error, should be int=xx,int=xx
			
先说这个Sharding item parameters '1' format error, should be int=xx,int=xx异常吧,这是在做动态添加调度任务的时候出现的,网上找了一会没 ...
 - LR12中针对WebServices协议的三种脚本开发模式
			
一,webservices协议简介 webservices是建立可交互操作的分布式应用程序的新平台,它通过一系列的标准和协议来保证程序之间的动态连接, 其中最基本的协议包括soap,wsdl,uddi ...
 - 0003.5-20180422-自动化第四章-python基础学习笔记--脚本
			
0003.5-20180422-自动化第四章-python基础学习笔记--脚本 1-shopping """ v = [ {"name": " ...
 - IDEA SpringBoot 打包(jar)
			
项目结构: sf-xxx-api sf-xxx-domain sf-xxx-common sf-xxx-web (web模块) 期望输出结果目录 bin/server.sh libs/**.jar,* ...
 - Linux机器重启情况查询
			
在实际开发过程中,有时可能发现有一些服务器的进程挂了,查询相关错误日志也没有头绪.此时需要考虑是否是由于机器重启导致的错误 使用命令last reboot来查看是否机器自动重启 导致服务器重启的原因有 ...
 - Linux环境配置文件的理解
			
百度百科: .bashrc这个文件主要保存个人的一些个性化设置,如命令别名.路径等.也即在同一个服务器上,只对某个用户的个性化设置相关. 示例: 编辑# User specific aliases a ...