为了方便,对于集合$S$,称$kequiv S(mod M)$当且仅当存在$xin S$使得$kequiv x(mod M)$
枚举红绿灯,对每一个点即限制$k$对$g_{i}+r_{i}$取模后的结果,同时相邻两个红绿灯限制相差是$o(1)$的,即可以提取出以下这个模型——
$n$次操作,每次操作给定$M$和$Ssubseteq [0,M)$,新增限制$k otequiv S(mod M)$
每次操作后,求随机整数$k$满足当前所有限制的概率
数据范围为$1le nle 500$,$1le Mle 100$
令$X=2^{3} imes 3^{2} imes 5 imes 7$,那么$forall 1le Mle 100,frac{M}{gcd(M,X)}$为一个素数的幂次或1
枚举随机整数$k$对$X$取模的余数$a$($0le a<X$),求出在满足给定限制下还满足$kequiv a(mod X)$的概率,将这些概率累加即为答案
令$k=a+tX$,问题即变为对于随机整数$t$,$a+tX$满足所有限制的概率,代入后限制$k otequiv S(mod M)$即可转换为$frac{X}{g}t otequiv S'(mod frac{M}{g})$
(其中$g=gcd(M,X)$,$S'={frac{x}{g}mid (gmid x)and (x+aequiv S(mod M))}$)
由于$gcd(frac{M}{g},frac{X}{g})=1$,再令$S'$所有元素乘上$frac{X}{g}$在模$frac{M}{g}$意义下的逆元,即$t otequiv S'(mod frac{M}{g})$
根据$X$的性质,$frac{M}{g}$必然是素数的幂次或1,假设是$p$的幂次,不妨转换为$p^{lfloorlog_{p}100 floor-ord_{p}(X)}$,此时相同素数的幂次必然都相同,直接对$S'$求并即可
(从同余的角度更容易理解此过程,但不同余方便实现)
最终,模数两两互素,每一个概率相乘即为答案
时间复杂度每一次都需要$o(MX)$去转化这个限制,总复杂度即$o(nMX)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 105 4 #define X 2520 5 struct del{ 6 int i,P,x; 7 }; 8 vector<int>v; 9 vector<del>v_del; 10 int n,x,r,g,p[N],visp[N],phi[N],tot[X][N],vis[X][N][N]; 11 double ans; 12 int gcd(int x,int y){ 13 if (!y)return x; 14 return gcd(y,x%y); 15 } 16 int pow(int n,int m,int mod){ 17 int s=n,ans=1; 18 while (m){ 19 if (m&1)ans=ans*s%mod; 20 s=s*s%mod; 21 m>>=1; 22 } 23 return ans; 24 } 25 void add(int p,int m,vector<int>v){ 26 int g=gcd(m,X),mm=m/g,P=mm,inv=pow(X/g,phi[mm]-1,mm); 27 if (P%2==0)P=8; 28 if (P%3==0)P=9; 29 for(int i=0;i<X;i++) 30 for(int j=0;j<v.size();j++){ 31 int x=(v[j]-i%m+m)%m; 32 if (x%g)continue; 33 x=x/g*inv%mm; 34 for(int k=0;k<P/mm;k++) 35 if (!vis[i][P][k*mm+x]){ 36 tot[i][P]++; 37 vis[i][P][k*mm+x]=1; 38 if (p)v_del.push_back(del{i,P,k*mm+x}); 39 } 40 } 41 ans=0; 42 for(int i=0;i<X;i++){ 43 double s=1; 44 for(int j=1;j<=100;j++)s*=1.0*(j-tot[i][j])/j; 45 ans+=s; 46 } 47 while (v_del.size()){ 48 del o=v_del.back(); 49 tot[o.i][o.P]--; 50 vis[o.i][o.P][o.x]=0; 51 v_del.pop_back(); 52 } 53 } 54 int main(){ 55 phi[1]=1; 56 for(int i=2;i<N;i++){ 57 if (!visp[i]){ 58 p[++p[0]]=i; 59 phi[i]=i-1; 60 } 61 for(int j=1;(j<=p[0])&&(i*p[j]<N);j++){ 62 visp[i*p[j]]=1; 63 if (i%p[j])phi[i*p[j]]=phi[i]*phi[p[j]]; 64 else{ 65 phi[i*p[j]]=phi[i]*p[j]; 66 break; 67 } 68 } 69 } 70 scanf("%d",&n); 71 for(int i=1;i<=n;i++){ 72 scanf("%d%d%d",&x,&r,&g); 73 v.clear(); 74 for(int j=0;j<r+g;j++) 75 if ((j+x)%(r+g)>=r)v.push_back(j); 76 add(1,r+g,v); 77 printf("%.9f ",ans/X); 78 v.clear(); 79 for(int j=0;j<r+g;j++) 80 if ((j+x)%(r+g)<r)v.push_back(j); 81 add(0,r+g,v); 82 } 83 printf("%.9f",ans/X); 84 }