题目链接
题目大意
定义运算⊗:
•设
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}
x⊗y=∏ipi∣ai−bi∣。
现在有一个长度为
n
(
1
≤
n
≤
1
0
6
)
n(1\leq n\leq 10^6)
n(1≤n≤106)的序列
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=1≤j,k≤n,j⊗k=i∑ajkc
其中
0
≤
a
i
≤
998244353
,
0
≤
c
≤
1
0
9
0\leq a_i\leq 998244353,0\leq c\leq 10^9
0≤ai≤998244353,0≤c≤109。
由于答案数据量很大,一次输出下式结果即可:
(
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}
x⊗y=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=1≤x,y≤n,xy=i,gcd(x,y)=1∑g=1∑min(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=1∑maxg(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;
}
总结
没什么好说的,思路理解了代码基本没难度。数学题,草稿纸上的题目,不用长时间盯着代码版。