题目大意
电影院观众席为 n×m 的方阵,其中 k 个座位 (r1,s1),⋯,(rk,sk) 已经被占。问从剩下的座位中,选择某一行的一个连续段(长度至少为 1)的方案数。
n,m≤105, 1≤k≤nm,给定 r1,s1,ar,br,as,bs,按如下方式生成剩余数据:
ri=(ri−1⋅ar+br)modnsi=(si−1⋅as+bs)modm
2s
题解
它说它是数据随机生成,它可不是随机生成的啊,一次函数,模 n,后来它说 k 是 O(nm) 的,看来是 有 循 环 节
这个 r 和 s 显然是有循环节的。为了方便处理,先把还没进入循环节的坐标((ri,si) 横纵坐标任意一个没有进入循环节就算这个坐标没有进入循环节)特殊标记出来(怎么用后面再说)。假设去掉这些坐标以后,起始坐标为 (r0,s0),r 序列的循环节长度为 pr,循环节为 r0,⋯,rpr−1;s 序列的循环节长度为 ps,循环节为 s0,⋯,sps−1。
这里会有 pr≤n, ps≤m。
对于 r0,暴力把这一行的所有纵坐标求出来(即 s0,sprmodps,s2prmodps,⋯,直到超出 k 的限制),这个时间是 O(gcd(pr,ps)ps) 的。求出来之后丢进一个 set 里,就可以维护出这一行的答案了(记得考虑没进循环节的特殊点)。
接下来最最重要的就是,发现有些行跟它是相似的!
考虑第 rpsmodpr 行,发现它的纵坐标序列跟 r0 的纵坐标序列大体相同,只有头尾有些不同。(因为纵坐标的循环节就是 ps,所以中间大部分纵坐标循环了一圈没有变化,不同的在于,r0 的最后几个纵坐标放到 rpsmodpr 里去可能超出了 k 的限制,rpsmodpr 可能在开头会比 r0 多几个。)
而头尾这些不同的元素数量是 O(⌈prps⌉) 的,可以用 O(⌈prps⌉) 的时间把 set 调整过来。
同理,第 r2psmodpr 行跟第 rpsmodpr 行也是这样相似的,第 r3psmodpr 跟第 r2psmodpr 行也是这样相似的……
因此 r0,⋯,rpr−1 共分成了 gcd(ps,pr) 个相似类,每个相似类的大小为 gcd(ps,pr)pr。每个相似类首先暴力求出初始一行的纵坐标序列,丢进 set 里,然后遍历这个相似类,调整 set 算答案。
暴力求初始纵坐标的时间复杂度为 O(gcd(ps,pr)⋅gcd(ps,pr)ps)=O(ps),set 调整的次数为 O(pr⋅⌈prps⌉)=O(ps),再加上 set 那么这题的复杂度就是 O(mlogm)。
代码
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); }
|