2021牛客多校#4 H-Convolution

题目链接

传送门

题目大意

定义运算⊗:
•设 p i p_i pi表示第 i i i个素数,若 x = ∏ i p i a i , y = ∏ i p i b i x=\prod_{i}p^{a_i}_{i} ,y=\prod_{i}p^{b_i}_{i} x=ipiai,y=ipibi,则 x ⊗ y = ∏ i p i ∣ a i − b i ∣ x⊗y=\prod_{i}p^{|a_i-b_i|}_{i} xy=ipiaibi
现在有一个长度为 n ( 1 ≤ n ≤ 1 0 6 ) n(1\leq n\leq 10^6) n(1n106)的序列 a a a
求满足下式的序列 b b b
b i = ∑ 1 ≤ j , k ≤ n , j ⊗ k = i a j k c b_i=\sum^{}_{1\leq j,k\leq n,j⊗k=i}a_jk^c bi=1j,kn,jk=iajkc
其中 0 ≤ a i ≤ 998244353 , 0 ≤ c ≤ 1 0 9 0\leq a_i\leq 998244353,0\leq c\leq 10^9 0ai998244353,0c109
由于答案数据量很大,一次输出下式结果即可:
( b 1 m o d    998244353 ) ⊗ ( b 2 m o d    998244353 ) . . . ⊗ ( b n m o d    998244353 ) (b_1\mod998244353)⊗(b_2\mod998244353)...⊗(b_n\mod998244353) (b1mod998244353)(b2mod998244353)...(bnmod998244353)

题解

由题意得, x = ∏ i p i b i x=\prod_ip_i^{b^i} x=ipibi运算即分解其质因数,通过 l c m lcm lcm g c d gcd gcd的性质可以得出 x ⊗ y = l c m ( x , y ) g c d ( x , y ) = x y g c d ( x , y ) 2 x\otimes y=\frac{lcm(x,y)}{gcd(x,y)}=\frac{xy}{gcd(x,y)^2} xy=gcd(x,y)lcm(x,y)=gcd(x,y)2xy
b i b_i bi的表达式可以转变为 b i = ∑ 1 ≤ x , y ≤ n , x y = i , g c d ( x , y ) = 1 ∑ g = 1 m i n ( n x , n y ) a x g ( y g ) 2 b_i=\sum_{1 \leq x,y \leq n,xy=i,gcd(x,y)=1}\sum_{g=1}^{min(\frac{n}{x},\frac{n}{y})}a_{xg}(yg)^2 bi=1x,yn,xy=i,gcd(x,y)=1g=1min(xn,yn)axg(yg)2
y y y项移至左边得 y 2 x 2 a x g ( x g ) 2 \frac{y^2}{x^2}a_{xg}(xg)^2 x2y2axg(xg)2
此时带入暴力求解即可,由于 a x g ( x g ) 2 a_{xg}(xg)^2 axg(xg)2要经常被使用所以我们打一个表来储存 d p x , m = ∑ g = 1 m a x g ( x g ) 2 dp_{x,m}=\sum_{g=1}^{m}a_{xg}(xg)^2 dpx,m=g=1maxg(xg)2其中 m = m i n ( n x , n y ) 且 ≤ n x m=min(\frac{n}{x},\frac{n}{y})且 \leq \frac{n}{x} m=min(xn,yn)xn
最后将求得的 b b b数组进行异或操作。
注意这题要求 k c k^c kc过大,所以用快速幂求解,本题为防爆,全程取模 m o d = 998244353 mod=998244353 mod=998244353。过程中遇到除法操作请用其费马,算其逆元,求其结果。

参考代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=1e6+5,mod=998244353;
ll gcd(ll a,ll b)
{
    return a%b==0?b:gcd(a%b,b);
}
ll pow(ll a,ll b)
{
    ll ret=1;
    while(b)
    {
        if(b&1)
            ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}
ll a[N],b[N],f[N],dp[N];
ll n,c;
int main()
{
    scanf("%lld %lld",&n,&c);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        f[i]=pow(1ll*i,c);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j*i<=n;j++)
            dp[j]=(dp[j-1]+a[i*j]*f[i*j]%mod)%mod;
        for(int j=1;j*i<=n;j++)
        {
            if(__gcd(i,j)!=1)
               continue;
            b[i*j]=(b[i*j]+f[j]*pow(f[i],mod-2)%mod*dp[min(n/i,n/j)]%mod)%mod;
        }
    }
    for(int i=2;i<=n;i++)
        b[i]^=b[i-1];
    printf("%lld\n",b[n]);
    return 0;
}

总结

没什么好说的,思路理解了代码基本没难度。数学题,草稿纸上的题目,不用长时间盯着代码版。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值