• 【UR #5】怎样跑得更快


    题目

    给定(n,c,d)和序列({b_i}),求一个序列({x_i})满足

    [sum_{j=1}^ngcd(i,j)^c imes m{lcm(i,j)^d} imes x_jequiv b_i(mod P ) ]

    不难将( m lcm(i,j))写成(frac{i imes j}{gcd(i,j)})

    [sum_{j=1}^ngcd(i,j)^{c-d}j^dx_jequiv b_i imes i^{-d}(mod P) ]

    套路枚举(gcd),之后套路反演一下,设(omega =c-d)

    [sum_{d|i}d^{omega}sum_{d|k}[k|i]mu(frac{k}{d})F(k)equiv b_i imes i^{-d}(mod P) ]

    其中(F(k)=sum_{k|t}x_tt^d)

    套路地进行简单和式变换

    [sum_{k|i}F(k)sum_{d|k}mu(frac{k}{d})d^{omega}equiv b_i imes i^{-d}(mod P) ]

    (g(n)=sum_{d|n}mu(frac{n}{d})d^{omega})

    上式即为

    [sum_{k|i}F(k)g(k)equiv b_i imes i^{-d}(mod P) ]

    不难发现就是一个函数叫做(F(k)g(k))卷上了一个(1)得到了右边那个函数,不妨称之为(B(i))

    (F(i)g(i)=(mu imes B)(i))

    于是(F(i)=frac{(mu imes B)(i)}{g(i)}),得到(F)之后再和(mu)卷一波就能求(x)

    (mu)完全可以用高维差分优化到(O(nlog log n)),所以要是写个线筛(i^k)和离线求逆元就是(O(qnlog log n))复杂度了

    显然我懒得写

    代码

    #include<bits/stdc++.h>
    #define re register
    const int maxn=1e5+5;
    const int mod=998244353;
    inline int dqm(int x){return x<0?x+mod:x;}
    inline int qm(int x) {return x>=mod?x-mod:x;}
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int f[maxn],p[maxn>>1],b[maxn],g[maxn],n,c,d;
    inline int ksm(int a,int b) {
    	b%=(mod-1);if(b<0) b+=mod-1;
    	int S=1;for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) S=1ll*S*a%mod;return S;
    }
    inline void work() {
    	for(re int i=1;i<=n;i++) b[i]=1ll*read()*ksm(i,-d)%mod;
        for(re int i=1;i<=p[0];++i) 
    		for(re int j=n/p[i];j;--j) b[j*p[i]]=dqm(b[j*p[i]]-b[j]);
    	for(re int i=1;i<=n;i++)
    		if(g[i]==0&&b[i]) {puts("-1");return;}else b[i]=1ll*b[i]*g[i]%mod;
    	for(re int i=1;i<=p[0];++i)
    		for(re int T=n/p[i],j=1;j<=T;++j) b[j]=dqm(b[j]-b[p[i]*j]);
    	for(re int i=1;i<=n;i++) printf("%d ",1ll*b[i]*ksm(i,-d)%mod);
    	puts("");
    }
    int main() {
    	n=read(),c=read(),d=read();c%=(mod-1),d%=(mod-1);
    	for(re int i=2;i<=n;i++) {
    		if(!f[i]) p[++p[0]]=i;
    		for(re int j=1;j<=p[0]&&p[j]*i<=n;++j) {
    			f[p[j]*i]=1;if(i%p[j]==0)break;
    		}
    	}
    	for(re int i=1;i<=n;i++) g[i]=ksm(i,c-d);
    	for(re int i=p[0];i;--i)
    		for(re int j=n/p[i];j;--j) g[p[i]*j]=dqm(g[p[i]*j]-g[j]);	
    	for(re int i=1;i<=n;i++) g[i]=ksm(g[i],mod-2);
    	for(re int Q=read();Q;--Q) work();return 0;
    }
    
  • 相关阅读:
    深入理解 C/C++ sizeof() 运算符
    Luogu2040 | 打开所有的灯 (广搜+状压)
    Intel 8086 标志寄存器及JCC指令表
    Intel 8086 常用汇编指令表
    PTA L2-029 | 特立独行的幸福 (打表+递归)
    C++中为什么要用指针,而不直接使用对象?
    c#中基本类型占用字节数
    c++TXT文件读入
    较为初始的学生成绩管理系统
    C++中各种数据成员及成员函数的定义及使用
  • 原文地址:https://www.cnblogs.com/asuldb/p/12026882.html
Copyright © 2020-2023  润新知