题目
思路
第
i
=
k
n
+
a
i=kn+a
i=kn+a 天,考虑两个灯是否相同,就可以检查二分值。即
∑
k
n
+
a
≤
t
[
p
a
≠
q
(
k
n
+
a
)
m
o
d
m
]
\sum_{kn+a\le t}[p_a\ne q_{(kn+a)\bmod m}]
kn+a≤t∑[pa=q(kn+a)modm]
设
k
n
m
o
d
m
=
x
0
kn\bmod m=x_0
knmodm=x0,实际上我们就要求
∑
a
[
p
a
≠
q
(
a
+
x
0
)
m
o
d
m
]
\sum_{a}[p_a\ne q_{(a+x_0)\bmod m}]
a∑[pa=q(a+x0)modm]
而 ( k + 1 ) n ≤ t (k+1)n\le t (k+1)n≤t 时, a a a 就没有限制了。所以多数时候 a a a 是无限制的。如果对于所有 x 0 x_0 x0 都求出这个值,就不需要二分了,直接用 k k k 暴力增,最后确定 t − k n t-kn t−kn 的值。所以这个无限制的问题怎么做?
正难则反,考虑统计有多少个是相等的。那么 p a = q b p_a=q_b pa=qb 会贡献到 x 0 = b − a x_0=b-a x0=b−a 上面去。显然这就是卷积——将 p p p 翻转即可。
问题是,下标的范围挺大的,而权值太多,就会出问题。考虑经典 “大小点”,设定阙值
M
M
M,当前权值数量不超过
M
M
M 就平方硬算,否则
m
log
m
m\log m
mlogm 卷积。显然复杂度是
O
(
m
M
+
m
2
log
m
M
)
≥
O
(
m
m
log
m
)
\mathcal O\left(mM+\frac{m^2\log m}{M}\right)\ge\mathcal O(m\sqrt{m\log m})
O(mM+Mm2logm)≥O(mmlogm)
发现会 T L E TLE TLE,然后我就想不出来了。考试结束后, H a n d I n D e v i l \sf HandInDevil HandInDevil 突然告诉我, p , q p,q p,q 中数字互不相同,所以每种权值都是最多出现 2 2 2 次……
所以就做到 O ( n + m ) \mathcal O(n+m) O(n+m) 了。这不读题的毛病,啥时候能改改!
代码
#include <bits/stdc++.h>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
typedef long long int_;
inline int_ readint(){
int_ a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline void writeint(int_ x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) writeint(x/10);
putchar((x-x/10*10)^48);
}
const int MaxN = 1000005;
int a[MaxN], b[MaxN], cnt[MaxN];
int A[MaxN], B[MaxN];
int main(){
int n = readint(), m = readint();
int_ k = readint();
int d = __gcd(n,m);
rep(i,1,n) a[A[i] = readint()] = i;
rep(i,1,m) b[B[i] = readint()] = i;
if(n > m){
swap(n,m), swap(a,b);
swap(A,B); // for convenience
}
rep(i,1,m<<1) if(a[i] && b[i])
++ cnt[(b[i]+m-a[i])%m];
int_ peri = 0; rep(i,0,m/d-1)
peri += n-cnt[1ll*i*n%m];
int_ ans = 1ll*n*m/d*((k-1)/peri);
k = (k-1)%peri+1; // period
rep(i,0,m/d-1)
if(k <= n-cnt[1ll*i*n%m]){
int t = 1ll*i*n%m;
for(int j=1; j<=n; ++j,++ans)
if(A[j] != B[(j+t-1)%m+1])
if((-- k) == 0) break;
++ ans; break;
}
else{
k -= (n-cnt[1ll*i*n%m]);
ans += n; // n more days
}
printf("%lld\n",ans);
return 0;
}