BZOJ 5510: [Tjoi2019]唱、跳、rap和篮球 OGF+NTT

本文深入探讨了高效生成函数的实现与多项式运算技巧,包括快速傅里叶变换(FFT)、逆元计算、多项式的乘法、加法、减法、除法等操作,以及如何利用这些技巧解决复杂的数学问题。

十分轻松的生成函数题. 

code: 

#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>
#define ll long long
#define ull unsigned long long
using namespace std;
namespace IO
{
    char buf[100000],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd()
    {
        int x=0; char s=nc();
        while(s<'0') s=nc();
        while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
        return x;
    }  
    void print(int x) {if(x>=10) print(x/10);putchar(x%10+'0');}
    void setIO(string s)
    {
        string in=s+".in";
        string out=s+".out";
        freopen(in.c_str(),"r",stdin);
        // freopen(out.c_str(),"w",stdout);
    }
};
const int G=3;
const int N=200005;
const int mod=998244353;            
int A[N],B[N],w[2][N],mem[N*100],*ptr=mem,tmpa[N],tmpb[N],aa[N],bb[N];   
inline int qpow(int x,ll y)
{
    int tmp=1;
    for(;y;y>>=1,x=(ll)x*x%mod)     if(y&1) tmp=(ll)tmp*x%mod;    
    return tmp;
}
inline int INV(int a) { return qpow(a,mod-2); } 
inline void ntt_init(int len)
{
    int i,j,k,mid,x,y;
    w[1][0]=w[0][0]=1,x=qpow(3,(mod-1)/len),y=qpow(x,mod-2);
    for (i=1;i<len;++i) w[0][i]=(ll)w[0][i-1]*x%mod,w[1][i]=(ll)w[1][i-1]*y%mod;  
}
void NTT(int *a,int len,int flag)
{
    int i,j,k,mid,x,y;        
    for(i=k=0;i<len;++i)
    {
        if(i>k)    swap(a[i],a[k]);
        for(j=len>>1;(k^=j)<j;j>>=1);
    }
    for(mid=1;mid<len;mid<<=1)     
        for(i=0;i<len;i+=mid<<1)
            for(j=0;j<mid;++j)   
            {
                x=a[i+j], y=(ll)w[flag==-1][len/(mid<<1)*j]*a[i+j+mid]%mod;
                a[i+j]=(x+y)%mod;
                a[i+j+mid]=(x-y+mod)%mod;
            }
    if(flag==-1)
    {
        int rev=INV(len);
        for(i=0;i<len;++i)    a[i]=(ll)a[i]*rev%mod;
    }
}       
inline void getinv(int *a,int *b,int len,int la)    
{
    if(len==1) { b[0]=INV(a[0]);   return; }
    getinv(a,b,len>>1,la);
    int l=len<<1,i;
    memset(A,0,l*sizeof(A[0]));       
    memset(B,0,l*sizeof(A[0]));
    memcpy(A,a,min(la,len)*sizeof(a[0]));                                               
    memcpy(B,b,len*sizeof(b[0]));      
    ntt_init(l);
    NTT(A,l,1),NTT(B,l,1);
    for(i=0;i<l;++i)  A[i]=((ll)2-(ll)A[i]*B[i]%mod+mod)*B[i]%mod;
    NTT(A,l,-1);                          
    memcpy(b,A,len<<2);   
}  
void get_dao(int *a,int *b,int len)
{
    for(int i=1;i<len;++i) b[i-1]=(ll)i*a[i]%mod;
    b[len-1]=0;
}              
void get_jifen(int *a,int *b,int len)
{
    for(int i=1;i<len;++i) b[i]=(ll)INV(i)*a[i-1]%mod;
    b[0]=0;
}
void get_ln(int *a,int *b,int len,int la)
{
    int l=len<<1,i;
    memset(tmpa,0,l<<2);
    memset(tmpb,0,l<<2);
    get_dao(a,tmpa,min(len,la));
    getinv(a,tmpb,len,la);
    ntt_init(l);    
    NTT(tmpa,l,1),NTT(tmpb,l,1);
    for(i=0;i<l;++i) tmpa[i]=(ll)tmpa[i]*tmpb[i]%mod;
    NTT(tmpa,l,-1);
    get_jifen(tmpa,b,len);
} 
void get_exp(int *a,int *b,int len,int la)
{
    if(len==1) { b[0]=1; return; }                     
    int l=len<<1,i;
    get_exp(a,b,len>>1,la);         
    for(i=0;i<l;++i)  aa[i]=bb[i]=0;
    for(i=0;i<(len>>1);++i) aa[i]=b[i];      
    get_ln(b,bb,len,len>>1);                                         
    for(i=0;i<len;++i) bb[i]=(ll)(mod-bb[i]+(i>=la?0:a[i]))%mod;                         
    bb[0]=(bb[0]+1)%mod;
    ntt_init(l);
    NTT(aa,l,1),NTT(bb,l,1);
    for(i=0;i<l;++i) aa[i]=(ll)aa[i]*bb[i]%mod;
    NTT(aa,l,-1);
    for(i=0;i<len;++i)  b[i]=aa[i];
}
struct poly
{
    int len,*a;
    poly(){}
    poly(int l) {len=l,a=ptr,ptr+=l; }     
    inline void rev() { reverse(a,a+len); }
    inline void fix(int l) {len=l,a=ptr,ptr+=l;}
    inline void get_mod(int l) { for(int i=l;i<len;++i) a[i]=0;  len=l;  }
    inline poly dao()
    { 
        poly re(len-1);
        for(int i=1;i<len;++i)  re.a[i-1]=(ll)i*a[i]%mod;  
        return re;
    }
    inline poly jifen()
    {
        poly c;
        c.fix(len+1); 
        c.a[0]=0;
        for(int i=1;i<=len;++i) c.a[i]=(ll)a[i-1]*INV(i)%mod;         
        return c;
    }    
    inline poly Inv(int l)
    {          
        int lim=1;
        while(lim<=l) lim<<=1;   
        poly b(lim);
        getinv(a,b.a,lim,len);
        b.get_mod(l);                                
        return b;                 
    }            
    inline poly ln(int l)
    {
        int lim=1;
        while(lim<=l) lim<<=1;               
        poly b(lim);
        get_ln(a,b.a,lim,len);
        b.get_mod(l);   
        return b;
    }                   
    inline poly exp(int l)
    {
        int lim=1;
        while(lim<=l) lim<<=1;
        poly b(lim);
        get_exp(a,b.a,lim,len);  
        b.get_mod(l);
        return b;
    }                         
    inline poly operator*(const poly &b) const
    {
        poly c(len+b.len-1);
        if(c.len<=500)
        {  
            for(int i=0;i<len;++i)
                if(a[i])   for(int j=0;j<b.len;++j)  c.a[i+j]=(c.a[i+j]+(ll)(a[i])*b.a[j])%mod;
            return c;
        }
        int n=1;
        while(n<(len+b.len)) n<<=1;
        memset(A,0,n<<2);
        memset(B,0,n<<2);
        memcpy(A,a,len<<2);                      
        memcpy(B,b.a,b.len<<2);           
        ntt_init(n); 
        NTT(A,n,1), NTT(B,n,1);
        for(int i=0;i<n;++i) A[i]=(ll)A[i]*B[i]%mod;
        NTT(A,n,-1);
        memcpy(c.a,A,c.len<<2);
        return c;
    }
    poly operator+(const poly &b) const
    {
        poly c(max(len,b.len));
        for(int i=0;i<c.len;++i)  c.a[i]=((i<len?a[i]:0)+(i<b.len?b.a[i]:0))%mod;
        return c;
    }
    poly operator-(const poly &b) const
    {
        poly c(len);
        for(int i=0;i<len;++i)
        {
            if(i>=b.len)   c.a[i]=a[i];
            else c.a[i]=(a[i]-b.a[i]+mod)%mod;
        }
        return c;
    }
    poly operator/(poly u)
    {
        int n=len,m=u.len,l=1;
        while(l<(n-m+1)) l<<=1;                    
        rev(),u.rev();     
        poly v=u.Inv(l);
        v.get_mod(n-m+1); 
        poly re=(*this)*v;
        rev(),u.rev();
        re.get_mod(n-m+1);  
        re.rev();
        return re;
    }
    poly operator%(poly u)
    {
        poly re=(*this)-u*(*this/u); 
        re.get_mod(u.len-1);
        return re;
    }              
}po[4],fin;      
#define MAX 100002  
int n; 
int fac[N],inv[N],num[N];   
void Initialize() 
{
    int i,j; 
    fac[0]=inv[0]=1; 
    for(i=1;i<MAX;++i) fac[i]=(ll)i*fac[i-1]%mod,inv[i]=INV(fac[i]);  
}         
int C(int x,int y) { return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; }      
int calc(int de) 
{
    int i,j; 
    for(i=0;i<4;++i) 
    {
        for(j=0;j<po[i].len;++j)  po[i].a[j]=0;   
        for(j=0;j<=num[i]-de;++j) po[i].a[j]=inv[j];     
    }         
    fin=po[0]*po[1]*po[2]*po[3];     
    return fin.a[n-4*de];   
}
int main() 
{
    // IO::setIO("input"); 
    int i,j,ans=0; 
    Initialize();       
    scanf("%d",&n);    
    for(i=0;i<4;++i) scanf("%d",&num[i]);             
    sort(num,num+4);   
    for(i=0;i<4;++i) po[i].fix(num[i]+1);  
    for(i=0;i<=num[0];++i) 
    {  
        int d=(i&1)?mod-1:1;     
        int det=calc(i);        
        (ans+=(ll)d*C(n-3*i,i)%mod*fac[n-4*i]%mod*det%mod)%=mod;  
    }
    printf("%d\n",ans);    
    return 0;   
}

  

该数据集通过合成方式模拟了多种发动机在运行过程中的传感器监测数据,旨在构建一个用于机械系统故障检测的基准资源,特别适用于汽车领域的诊断分析。数据按固定时间间隔采集,涵盖了发动机性能指标、异常状态以及工作模式等多维度信息。 时间戳:数据类型为日期时间,记录了每个数据点的采集时刻。序列起始于2024年12月24日10:00,并以5分钟为间隔持续生成,体现了对发动机运行状态的连续监测。 温度(摄氏度):以浮点数形式记录发动机的温度读数。其数值范围通常处于60至120摄氏度之间,反映了发动机在常规工况下的典型温度区间。 转速(转/分钟):以浮点数表示发动机曲轴的旋转速度。该参数在1000至4000转/分钟的范围内随机生成,符合多数发动机在正常运转时的转速特征。 燃油效率(公里/升):浮点型变量,用于衡量发动机的燃料利用效能,即每升燃料所能支持的行驶里程。其取值范围设定在15至30公里/升之间。 振动_X、振动_Y、振动_Z:这三个浮点数列分别记录了发动机在三维空间坐标系中各轴向的振动强度。测量值标准化至0到1的标度,较高的数值通常暗示存在异常振动,可能与潜在的机械故障相关。 扭矩(牛·米):以浮点数表征发动机输出的旋转力矩,数值区间为50至200牛·米,体现了发动机的负载能力。 功率输出(千瓦):浮点型变量,描述发动机单位时间内做功的速率,取值范围为20至100千瓦。 故障状态:整型分类变量,用于标识发动机的异常程度,共分为四个等级:0代表正常状态,1表示轻微故障,2对应中等故障,3指示严重故障。该列作为分类任务的目标变量,支持基于传感器数据预测故障等级。 运行模式:字符串类型变量,描述发动机当前的工作状态,主要包括:怠速(发动机运转但无负载)、巡航(发动机在常规负载下平稳运行)、重载(发动机承受高负荷或高压工况)。 数据集整体包含1000条记录,每条记录对应特定时刻的发动机性能快照。其中故障状态涵盖从正常到严重故障的四级分类,有助于训练模型实现故障预测与诊断。所有数据均为合成生成,旨在模拟真实的发动机性能变化与典型故障场景,所包含的温度、转速、燃油效率、振动、扭矩及功率输出等关键传感指标,均为影响发动机故障判定的重要因素。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值