洛谷 P6261 - [ICPC2019 WF]Traffic Blights(思维题)

洛谷题面传送门

首先不难发现周期是 \(M=\text{lcm}(r_1+g_1,r_2+g_2,r_3+g_3,\cdots,r_n+g_n)\)​​​​,也就是说问题等价于求从 \([0,M-1]\)​​​​ 任选一个数 \(X\)​​​​,满足 \(\forall i\in[1,n],(X+x_i)\bmod (r_i+g_i)\ge g_i\)​​​​ 的概率。

考虑一种特殊情况:\(r_i+g_i\) 两两互质,根据 CRT 的知识可以证明,对于 \(\forall\{a_n\},0\le a_i<r_i+g_i\),都可以找到一个序列 \(X\) 满足 \((X+x_i)\bmod (r_i+g_i)=a_i\),换句话说,对于任意序列 \(\{a_n\}\),满足 \(\forall i,(X+x_i)\bmod (r_i+g_i)=a_i\) 的概率都是相同的,为 \(\prod\limits_{i=1}^n\dfrac{g_i}{r_i+g_i}\)。因此总概率就可以直接按 \(\prod\limits_{i=1}^n\dfrac{g_i}{r_i+g_i}\) 来计算。

考虑将普遍的情况转化为这种情况,由于 \(r_i+g_i\le 100\),因此每个数最多只有一个 \(>10\) 的质因子。这样,我们取 \(V=2^6·3^4·5^2·7^2=6350400\),然后将每个 \([0,M-1]\) 中的数写成 \(kV+b(b<V)\) 的形式。考虑枚举 \(b\),这样根据同余论,如果我们把 \(k\) 当作变量,那么 \(kV+b\bmod (r_i+g_i)\) 的周期为 \(\dfrac{r_i+g_i}{\gcd(r_i+g_i,V)}\)。显然,由于 \(2^7>100,3^5>100,5^3>100,7^3>100\)\(\dfrac{r_i+g_i}{\gcd(r_i+g_i,V)}\) 肯定不含质因子 \(2,3,5,7\)。故这个数要么为 \(1\),要么为 \(>10\) 的质数。如果我们把大小相同的周期当作一类,那么不同类之间周期长度肯定是两两互质的。这样我们再对于每一类周期长度 \(l\),实时维护有多少个 \(\bmod l\) 的位置是合法的,设为 \(c_l\),那么对于这种情况合法的概率就是 \(\prod\limits_{l}\dfrac{c_l}{l}\),实时维护一下即可,时间复杂度 \(6350400·n·(r_i+b_i)\),无法通过。

继续优化。事实上,我们其实并不一定要让所有周期都是质数。我们发现如果一个周期是另一个周期的幂,那么我们将小的周期自动与大的周期对齐也可以转化为上一种情况,因此我们也可以取合适的 \(V\) 使得 \(\dfrac{r_i+g_i}{\gcd(r_i+g_i,V)}\) 都是质数或质数的幂,取 \(V=\text{lcm}(1,2,3,\cdots,10)\) 即可。这样复杂度就降到了 \(2520·n·(r_i+b_i)\)

const int MAXN = 500;
const int MAXV = 100;
int n, x[MAXN + 5], r[MAXN + 5], g[MAXN + 5];
bool able[MAXN + 5][MAXV + 5];
double p[MAXN + 5];
int getmax(int x) {return (x == 2) ? 8 : ((x == 4) ? 8 : ((x == 3) ? 9 : x));}
void calc(int x) {
	p[0] += 1; double prd = 1; static bool die[MAXV + 5][MAXV * 5 + 5];
	memset(die, 0, sizeof(die));
	for (int i = 1; i <= n; i++) {
		int cnt = 0, tot = 0;
		int d = __gcd(2520, r[i] + g[i]), md = (r[i] + g[i]) / d;
		int rst = getmax(md), mul = rst / md;
		for (int j = 0; j < md; j++) for (int k = 0; k < mul; k++) {
			if (!die[rst][j + k * md]) {
				if (able[i][(j * 2520 + x) % (r[i] + g[i])]) cnt++;
				else die[rst][j + k * md] = 1;
				tot++;
			}
		}
		if (!tot) break;
		prd = 1.0 * prd * cnt / tot;
		p[i] += prd;
	}
}
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%d%d%d", &x[i], &r[i], &g[i]);
	for (int i = 1; i <= n; i++) for (int j = r[i]; j < r[i] + g[i]; j++)
		able[i][(j - x[i] % (r[i] + g[i]) + r[i] + g[i]) % (r[i] + g[i])] = 1;
	for (int i = 0; i < 2520; i++) calc(i);
	for (int i = 0; i <= n; i++) p[i] /= 2520;
	for (int i = 1; i <= n + 1; i++) printf("%.10lf\n", p[i - 1] - p[i]);
	return 0;
}
/*
4
0 15 49
0 13 19
0 33 63
0 27 53
*/
posted @ 2022-01-12 23:32  tzc_wk  阅读(142)  评论(0)    收藏  举报