bzoj3992 [SDOI2015]序列统计(NTT快速幂)

bzoj3992 [SDOI2015]序列统计

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=3992
题意:
小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S。
小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。

数据范围
1<=N<=1e9,3<=M<=8000,M为质数,1<=x<=M-1,输入数据保证集合S中元素不重复,集合中的数属于[0,m-1]。

题解:

要求数的乘积为m,似乎很不好处理。
但是根据 ln xy=ln x+ln y l n   x y = l n   x + l n   y ,又因为m是质数,
可以求出原根g,用 gind[s] g i n d [ s ] 来表示集合内的数,把 s s 替换成ind[s]就把乘法转换成了加法。

于是答案就是构造出的多项式的n次幂的第ind[x]项系数。
注意由于求的是”乘积mod M的值等于x”,就是ind的乘积mod M-1 的值等于x,因此对于 i(i>=m1) i ( i >= m − 1 ) 的系数需要清零加到i%(m-1)项去。

学习了一发NTT。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int mod=1004535809;//479*2^21  g=3
const int N=30000;
int n,m,X,s,g,R[N],len=1,p=0,iv,G;
int ind[N],a[N],b[N],w1[N],w2[N],omg[N],_omg[N];
int modpow(int A,int B,int p)
{
    int ret=1; int base=A;
    for(;B;B>>=1)
    {
        if(B&1) ret=(1LL*ret*base)%p;
        base=(1LL*base*base)%p;
    }
    return ret;
}
inline int getg()
{
    for(int i=1,j;i<=m-1;i++)
    {
        for(j=1;j<=m-1;j++) {int x=modpow(i,j,m); if(x==1) break;}
        if(j==m-1) return i;
    }
    return -1;
}
void NTT(int *x,int opt)
{
    for(int i=0;i<len;i++) if(i<R[i]) swap(x[i],x[R[i]]);
    int *w; if(opt==1) w=omg; else w=_omg;
    for(int L=2;L<=len;L<<=1)
    {
        int l=L>>1; 
        for(int j=0;j<len;j+=L)
        for(int i=0;i<l;i++)
        {
            int y=(1LL*w[len/L*i]*x[i+j+l])%mod;
            x[i+j+l]=(x[i+j]-y+mod)%mod;
            x[i+j]=(x[i+j]+y)%mod;
        }
    }
    if(opt==-1) {for(int i=0;i<len;i++) x[i]=(1LL*x[i]*iv)%mod;}
}
void solve(int *A,int *B,int *C)
{
    for(int i=0;i<=len;i++) w1[i]=A[i],w2[i]=B[i];
    NTT(w1,1); NTT(w2,1);
    for(int i=0;i<len;i++) w1[i]=(1LL*w1[i]*w2[i])%mod,C[i]=0;
    NTT(w1,-1);
    for(int i=0;i<len;i++) C[i%(m-1)]=(C[i%(m-1)]+w1[i])%mod;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&X,&s);
    g=getg(); G=3;
    for(int i=1;i<=m-1;i++) ind[modpow(g,i,m)]=i; ind[1]=0;
    for(int i=1;i<=s;i++) {int x; scanf("%d",&x); if(x%m){a[ind[x%m]]=1;b[ind[x%m]]=1;}}
    for(p=0,len=1;len<2*m;len<<=1,p++); iv=modpow(len,mod-2,mod);
    R[0]=0; for(int i=1;i<len;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(p-1));
    omg[0]=1; omg[1]=modpow(G,(mod-1)/len,mod);
    for(int i=2;i<=len;i++) omg[i]=(1LL*omg[1]*omg[i-1])%mod;
    for(int i=0;i<len;i++) _omg[i]=omg[len-i];
    for(n--;n;n>>=1)
    {
        if(n&1) solve(a,b,a);
        solve(b,b,b);
    }
    printf("%d\n",a[ind[X]]);
    return 0;
}
MATLAB主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性内容概要:本文主要介绍了一种在MATLAB环境下实现的主动噪声和振动控制算法,该算法针对较大的次级路径变化具有较强的鲁棒性。文中详细阐述了算法的设计原理与实现方法,重点解决了传统控制系统中因次级路径动态变化导致性能下降的问题。通过引入自适应机制和鲁棒控制策略,提升了系统在复杂环境下的稳定性和控制精度,适用于需要高精度噪声与振动抑制的实际工程场景。此外,文档还列举了多个MATLAB仿真实例及相关科研技术服务内容,涵盖信号处理、智能优化、机器学习等多个交叉领域。; 适合人群:具备一定MATLAB编程基础和控制系统理论知识的科研人员及工程技术人员,尤其适合从事噪声与振动控制、信号处理、自动化等相关领域的研究生和工程师。; 使用场景及目标:①应用于汽车、航空航天、精密仪器等对噪声和振动敏感的工业领域;②用于提升现有主动控制系统对参数变化的适应能力;③为相关科研项目提供算法验证与仿真平台支持; 阅读建议:建议读者结合提供的MATLAB代码进行仿真实验,深入理解算法在不同次级路径条件下的响应特性,并可通过调整控制参数进一步探究其鲁棒性边界。同时可参考文档中列出的相关技术案例拓展应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值