[gym102511K]Traffic Blights

为了方便,对于集合$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 } 
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14669487.html