2021牛客暑期多校训练营4 H题

2021牛客暑期多校训练营4 H题

七月 27, 2021

题目概述

考虑$x=\prod_{i}p_i^{a_i}$,$y=\prod_{i}p_i^{b_i}$.定义$x \bigotimes y$=$\prod_{i}p_i^{|a_i-b_i|}$,现在给定一个数列$a[1…n]$,求出

分析与解

首先通过$|a_i-b_i|=max(a_i,b_i)-min(a_i,b_i)$来理解这个定义本质是$\frac{lcm(a,b)}{gcd(a,b)}$,故进一步得到

那么不妨令

故

因此

由此可见后面这个$gcd$的部分可以通过对于一个数枚举其倍数预处理得到,其复杂度为

前面这个$s$的枚举是$O(n\sqrt n)$,但并不满。因此总复杂度是可以接受的。

此外,对于$s,t$并没有大小之分,但是需要保证$s \cdot gcd ,t \cdot gcd \leq n$,因此需要在上述计算中选择较小的$gcd$上限来运算。

注意事项

本题在考场上低级错误在于快速幂。

枚举因子时sqrt应当提前算出!

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 998244353;
#define MAXN 1001000
#define min(a,b) (a) < (b) ? (a) : (b)
int mread() {
int ret=0,f=1;
char c=getchar();
while(c<'0' || c>'9') {
if(c=='-')f=-1;
c=getchar();
}
do {
ret=ret*10+c-'0';
c=getchar();
} while('0'<=c && c<='9');
return ret*f;
}
LL quick_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;
}
int gcd(int a,int b) {
if(b==0)return a;
return gcd(b,a%b);
}
LL b[MAXN];
int a[MAXN];
int n,c;
vector<LL> rela[MAXN];
LL my_pow[MAXN];
int main() {
// freopen("H.in","r",stdin);
LL sum=0;
LL now;
int s,t,qrt;
n=mread(),c=mread();
for(int i=1; i<=n; i++)a[i]=mread();
for(int i=1; i<=n; i++)my_pow[i]=quick_pow(i,c);
for(int i=1; i<=n; i++) {
now=0;
for(int j=i,k=1; j<=n; j+=i,k++) { //gcd enum
now=(now+1ll*a[j]*my_pow[k]%MOD+MOD)%MOD;
rela[i].push_back(now);
}
}
for(int i=1; i<=n; i++) {
qrt=sqrt((double)i);
for(int j=1; j<=qrt; j++) {
if(i%j!=0)continue;
s=j,t=i/j;
if(gcd(s,t)!=1)continue;
if(s!=t) {
b[i]=(b[i]+1ll*my_pow[t]*rela[s][min(n/s,n/t)-1]%MOD)%MOD;
b[i]=(b[i]+1ll*my_pow[s]*rela[t][min(n/s,n/t)-1]%MOD)%MOD;
} else b[i]=(b[i]+1ll*my_pow[s]*rela[s][min(n/s,n/t)-1]%MOD)%MOD;
}
}
for(int i=1; i<=n; i++)sum=sum^b[i];
printf("%lld\n",sum);
return 0;
}