• LOJ


    题目

    传送门

    解法

    算是单位根反演的经典应用吧。

    首先知道有一个求多项式特定倍数的系数和公式((k) 倍):

    [sum_{i=0}^{frac{n}{k}}[x^{ik}]f(x)=frac{1}{k}sum_{i=0}^{k-1}f(omega_k^i) ]

    对于这道题可以转化成这个柿子:

    [sum_{i=0}^3 a_isum_{j=0}^n [j ext{mod} 4=i] imes C(n,j) imes s^j ]

    这样我们构造一个多项式 (f) 使得 (C(n,i) imes s^i) 为第 (i) 项的系数就可以用单位根反演快速求出符合条件的系数和了。

    [f(x)=sum_{i=0}^n C(n,i) imes s^i imes x^i imes 1^{n-i} ]

    [=(sx+1)^n ]

    还有一个问题,上面的系数和公式只计算 (i ext{mod} 4=0),而我们还需要统计余数为 (1,2,3) 的情况。

    不过我们发现,多项式 (g(x)=sum_{i=0}^n a_ix^i) 如果整体除掉一个 (x) 即为 (g(x)div x=sum_{i=1}^n a_ix^{i-1})。容易发现这相当于系数整体往左移了一位,那么原先 ( ext{mod} 4=1) 的系数现在 ( ext{mod} 4=0),就可以计算了。

    具体就是枚举余数 (i),对于每个 (i) 系数和就是

    [frac{1}{4}sum_{j=0}^{4-1}frac{f(omega_4^j)}{omega_4^{ij ext{mod} 4}} ]

    时间复杂度 (mathcal O(16 imes T))

    代码

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    
    const int mod=998244353;
    
    int s,a[5],w[5],ans,tmp,inv4,g;
    long long n;
    
    int qkpow(int x,long long y) {
    	int r=1;
    	while(y) {
    		if(y&1) r=1ll*r*x%mod;
    		x=1ll*x*x%mod; y>>=1;
    	}
    	return r;
    }
    
    int main() {
    	w[0]=1,g=qkpow(3,(mod-1)/4),inv4=qkpow(4,mod-2);
    	rep(i,1,3) w[i]=1ll*w[i-1]*g%mod;
    	for(int T=read(9);T-->0;) {
    		n=read(9ll),s=read(9); ans=0;
    		rep(i,0,3) a[i]=read(9);
    		rep(i,0,3) {
    			tmp=0;
    			rep(j,0,3) tmp=(tmp+1ll*qkpow((1ll*s*w[j]%mod+1)%mod,n)*qkpow(w[i*j%4],mod-2)%mod)%mod;
    			tmp=1ll*tmp*inv4%mod;
    			ans=(ans+1ll*a[i]*tmp%mod)%mod;
    		}
    		print(ans,'
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux之 awk
    linux之 sed命令
    HBase源码分析之WAL
    oracle之 单实例监听修改端口
    oracle之 ORA-12557: TNS: 协议适配器不可加载
    oracle之 反向键索引
    oracle之 AWR固定基线
    oracle之 如何 dump logfile
    oracle 之 CLUSTER_INTERCONNECTS is not set to the recommended value
    oracle之 变更OS时间对数据库的影响
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14409246.html
Copyright © 2020-2023  润新知