【题 解】 CF109B Lucky Probability

Escribir esta solución es puramente para la contribución de la comunidad del agua

Título

Ir directamente al portal

análisis

Descubrimos que, aunque el rango dado en el título es muy grande, no hay muchos "números de la suerte" incluidos, por lo que podemos considerar enumerar kk adyacentesk números de la suerte, y contienen acumulativamente estekkEl número total de k intervalos. Finalmente, dividir el número de intervalos que cumplen las condiciones por el número total de intervalos es la probabilidad requerida.

La idea es así de simple, pero los detalles son más complicados. Primero supongamos que enumeramos kkLos extremos izquierdo y derecho de k números se numerani, ji, ji ,j, 用num [i] num [i]n u m [ i ] significa eliii es un número de la suerte, entonces hay algunos puntos a tener en cuenta:

Primero, el intervalo donde se encuentra el punto final izquierdo del intervalo que cumple la condición es [num [i - 1] + 1, num [i]] ∩ [pl, pr] [num [i-1] + 1, num [i]] \ cap [pl , pr][ n u m [ i-1 ]+1 ,n u m [ i ] ][ p l ,p r ] , el rango del punto final derecho es[num [j], num [j + 1] - 1] ∩ [vl, vr] [num [j], num [j + 1] -1] \ cap [vl , vr][ n u m [ j ] ,n u m [ j+1 ]-1 ][ v l ,v r ] , pero también es necesario ponerpl, pr pl, prp l ,p rvl, vr vl, vrv l ,v r Intercambiar respuestas estadísticas. El codigo es

		ans += calc(num[i-1]+1, num[i], pl, pr)*calc(num[j], num[j+1]-1, vl, vr);
		ans += calc(num[j], num[j+1]-1, pl, pr)*calc(num[i-1]+1, num[i], vl, vr);

Donde calc (l, r, x, y) calc (l, r, x, y)c a l c ( l ,r ,x ,y ) se utiliza para calcular el intervalo[l, r] [l, r][ l ,r ][x, y] [x, y][ x ,y ] intersección.

Así que terminaste de escribir el código con entusiasmo, solo para encontrar el sonido WA

Luego encontramos que habrá duplicados: por ejemplo, 6 8 6 8 1este conjunto de datos, porque ponemos pl, pr pl, prp l ,p rvl, vr vl, vrv l ,Calcule de nuevo después de que v r intercambie posiciones, entonces es equivalente a[7, 7] [7,7][ 7 ,7 ] Este intervalo se calculó dos veces y hubo una duplicación.

Entonces, ¿cómo evitamos la duplicación? No es difícil encontrar que esta situación solo ocurrirá cuando k = 1 k = 1k=Aparece en 1 , y el único número en el intervalo es un número de la suerte. Luego, simplemente agregamos una oración especial debajo del código original. (No olvide que este intervalo debe cumplir con los requisitos)

    ans += calc(num[i-1]+1, num[i], pl, pr)*calc(num[j], num[j+1]-1, vl, vr);
    ans += calc(num[j], num[j+1]-1, pl, pr)*calc(num[i-1]+1, num[i], vl, vr);
    if(k == 1) {
    
    
        if(calc(pl,pr,num[i],num[i]) && calc(vl,vr,num[i],num[i]))	//必须符合条件,否则根本不会计算
            ans--;
    }

Para que pueda pasar felizmente por este problema maligno impopular .

Código completo

#include <bits/stdc++.h>
#define ll long long
using namespace std;

vector<ll> num;
int n;
ll pl, pr, vl, vr, k;
ll ans = 0;

void dfs(ll x) {
    
    		//无脑预处理
	if(x >= 1e9) return;
	num.push_back(x);
	dfs(x*10+4);
	dfs(x*10+7);
}

inline ll calc(ll l, ll r, ll x, ll y) {
    
    		//计算区间重复长度
	if(r < x || l > y) return 0;
	if(l>r || x>y) return 0;
	if(l >= x && l <= y) return min(r, y)-l+1;
	if(r >= x && r <= y) return r-max(l, x)+1;
	if(l < x && r > y) return y-x+1;
}

int main() {
    
    
	dfs(0);
	n = num.size();
	num.push_back(1e16);
	sort(num.begin(), num.end());
	cin >> pl >> pr >> vl >> vr >> k;
	for(int i = 1; i+k-1 <= n; i++) {
    
    
		if(num[i] > vr && num[i]>pr) break;		//(应该)可写可不写的特判break
		int j = i+k-1;
		ans += calc(num[i-1]+1, num[i], pl, pr)*calc(num[j], num[j+1]-1, vl, vr);
		ans += calc(num[j], num[j+1]-1, pl, pr)*calc(num[i-1]+1, num[i], vl, vr);
		if(k == 1) {
    
    
			if(calc(pl, pr, num[i], num[i]) && calc(vl, vr, num[i], num[i]))
				ans--;
		}
	}
	printf("%.12lf", ans*1.0/(vr-vl+1)/(pr-pl+1), 1.0);

	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/qq_30115697/article/details/90208951
Recomendado
Clasificación