【XVIII Open Cup E.V. Pankratiev. Grand Prix of Gomel E】Exit Song 题解

题目大意

  电影院观众席为 n×mn \times m 的方阵,其中 kk 个座位 (r1,s1),,(rk,sk)(r_1,s_1),\cdots,(r_k,s_k) 已经被占。问从剩下的座位中,选择某一行的一个连续段(长度至少为 11)的方案数。

  n,m105,  1knmn,m \leq 10^5,\ \ 1 \le k \le nm,给定 r1,s1,ar,br,as,bsr_1,s_1,a_r,b_r,a_s,b_s,按如下方式生成剩余数据:

ri=(ri1ar+br)modnsi=(si1as+bs)modmr_i = (r_{i-1} \cdot a_r + b_r) \bmod n \\ s_i = (s_{i-1} \cdot a_s + b_s) \bmod m

  2s

题解

  它说它是数据随机生成,它可不是随机生成的啊,一次函数,模 nn,后来它说 kkO(nm)O(nm) 的,看来是 有 循 环 节

  这个 rrss 显然是有循环节的。为了方便处理,先把还没进入循环节的坐标((ri,si)(r_i,s_i) 横纵坐标任意一个没有进入循环节就算这个坐标没有进入循环节)特殊标记出来(怎么用后面再说)。假设去掉这些坐标以后,起始坐标为 (r0,s0)(r_0,s_0)rr 序列的循环节长度为 prpr,循环节为 r0,,rpr1r_0,\cdots,r_{pr-1}ss 序列的循环节长度为 psps,循环节为 s0,,sps1s_0,\cdots,s_{ps-1}
  这里会有 prn, psmpr \le n,\ ps \le m

  对于 r0r_0,暴力把这一行的所有纵坐标求出来(即 s0,sprmodps,s2prmodps,s_0,s_{pr \bmod ps},s_{2pr \bmod ps},\cdots,直到超出 kk 的限制),这个时间是 O(psgcd(pr,ps))O(\frac{ps}{\gcd(pr,ps)}) 的。求出来之后丢进一个 set 里,就可以维护出这一行的答案了(记得考虑没进循环节的特殊点)。
  接下来最最重要的就是,发现有些行跟它是相似的!
  考虑第 rpsmodprr_{ps \bmod pr} 行,发现它的纵坐标序列跟 r0r_0 的纵坐标序列大体相同,只有头尾有些不同。(因为纵坐标的循环节就是 psps,所以中间大部分纵坐标循环了一圈没有变化,不同的在于,r0r0 的最后几个纵坐标放到 rpsmodprr_{ps \bmod pr} 里去可能超出了 kk 的限制,rpsmodprr_{ps\bmod pr} 可能在开头会比 r0r_0 多几个。)
  而头尾这些不同的元素数量是 O(pspr)O(\lceil \frac{ps}{pr} \rceil) 的,可以用 O(pspr)O(\lceil \frac{ps}{pr} \rceil) 的时间把 set 调整过来。
  同理,第 r2psmodprr_{2ps \bmod pr} 行跟第 rpsmodprr_{ps \bmod pr} 行也是这样相似的,第 r3psmodprr_{3ps \bmod pr} 跟第 r2psmodprr_{2ps \bmod pr} 行也是这样相似的……
  因此 r0,,rpr1r_0,\cdots,r_{pr-1} 共分成了 gcd(ps,pr)\gcd(ps,pr) 个相似类,每个相似类的大小为 prgcd(ps,pr)\frac{pr}{\gcd(ps,pr)}。每个相似类首先暴力求出初始一行的纵坐标序列,丢进 set 里,然后遍历这个相似类,调整 set 算答案。
  暴力求初始纵坐标的时间复杂度为 O(gcd(ps,pr)psgcd(ps,pr))=O(ps)O(\gcd(ps,pr) \cdot \frac{ps}{\gcd(ps,pr)}) = O(ps),set 调整的次数为 O(prpspr)=O(ps)O(pr \cdot \lceil \frac{ps}{pr} \rceil) = O(ps),再加上 set 那么这题的复杂度就是 O(mlogm)O(m \log m)

代码

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxn=1e5+5;

int n,m,r0,s0,ar,br,as,bs;
LL k;

int visr[maxn],viss[maxn],r[maxn],s[maxn],pr,ps;
vector<int> spc[maxn];
void make_period()
{
while (k && (!visr[r0] || !viss[s0]))
{
spc[r0].push_back(s0);
visr[r0]=1, viss[s0]=1;
r0=(r0*(LL)ar+br)%n;
s0=(s0*(LL)as+bs)%m;
k--;
}

memset(visr,0,sizeof(visr));
for(; !visr[r0]; r0=(r0*(LL)ar+br)%n) visr[r0]=1, r[pr++]=r0;
memset(viss,0,sizeof(viss));
for(; !viss[s0]; s0=(s0*(LL)as+bs)%m) viss[s0]=1, s[ps++]=s0;
}

inline LL sum1(LL x) {return (x*(x+1))>>1;}

LL ans1,ans;
set<int> S;
void add(int x)
{
int l,r;
set<int>::iterator it=S.upper_bound(x);
r=*it;
it--;
l=*it;
ans1+=sum1(x-l-1)+sum1(r-x-1)-sum1(r-l-1);
S.insert(x);
}
void del(int x)
{
int l,r;
set<int>::iterator it=S.lower_bound(x);
it--;
l=*it;
it++;it++;
r=*it;
it--;
ans1+=sum1(r-l-1)-sum1(x-l-1)-sum1(r-x-1);
S.erase(it);
}
void calc_ans(int i)
{
for(int x:spc[i]) add(x);
ans+=ans1;
for(int x:spc[i]) del(x);
}

int main()
{
scanf("%d %d %lld",&n,&m,&k);
scanf("%d %d %d",&r0,&ar,&br);
scanf("%d %d %d",&s0,&as,&bs);

make_period();

memset(visr,0,sizeof(visr));
memset(viss,0,sizeof(viss));
int timeStamp=0;
fo(i,0,pr-1) if (!visr[r[i]])
{
timeStamp++;
ans1=sum1(m);
S.clear();
S.insert(-1), S.insert(m);
deque<int> Q;
LL curTime=i+1;
for(int j=i%ps; curTime<=k; (j+=pr)%=ps, curTime+=pr)
{
if (viss[j]==timeStamp) break;
Q.push_back(j);
viss[j]=timeStamp;
add(s[j]);
}

for(int ii=i; !visr[r[ii]]; (ii+=ps)%=pr)
{
visr[r[ii]]=1;
if (Q.empty())
{
curTime=ii+1;
for(int j=ii%ps; curTime<=k; (j+=pr)%=ps, curTime+=pr)
{
Q.push_back(j);
add(s[j]);
}
} else
{
while (Q.front()!=ii%ps)
{
int j=((Q.front()-pr)%ps+ps)%ps;
add(s[j]);
Q.push_front(j);
}
}
while (!Q.empty() && ii+1+(Q.size()-1)*(LL)pr>k)
{
del(s[Q.back()]);
Q.pop_back();
}
calc_ans(r[ii]);
}
}
ans1=sum1(m);
S.clear();
S.insert(-1), S.insert(m);
fo(i,0,n-1) if (!visr[i]) calc_ans(i);

printf("%lld\n",ans);
}