随机在[a,b] 选取一个数,随即在[c,d]选取一个数
问 x + y 取模 p 同余 n 的概率
其实就是计数问题。关键在于如何计数可以不重不漏。
麻烦点在于分类讨论。对于这样的区间问题,先简化为0 , x 的区间。
这里用到容斥原理,第一次做这样的题,不是很容易想到。
分类讨论相对来说感觉还算简单?只要耐心讨论,总错不了
#pragma warning(disable:4996) #include<iostream> #include<algorithm> #include<bitset> #include<tuple> #include<unordered_map> #include<fstream> #include<iomanip> #include<string> #include<cmath> #include<cstring> #include<vector> #include<map> #include<set> #include<list> #include<queue> #include<stack> #include<sstream> #include<cstdio> #include<ctime> #include<cstdlib> #define pb push_back #define INF 0x3f3f3f3f #define inf 0x7FFFFFFF #define moD 1000000003 #define pii pair<ll,ll> #define eps 1e-8 #define equals(a,b) (fabs(a-b)<eps) #define bug puts("bug") #define re register #define fi first #define se second typedef long long ll; typedef unsigned long long ull; const ll MOD = 1e6 + 7; const int maxn = 3e5 +5; const double Inf = 10000.0; const double PI = acos(-1.0); using namespace std; ll a, b, c, d, p, m; ll f(ll a, ll b) { if (a < 0 || b < 0) return 0; ll ans = (a / p) * (b / p) * p; ll ma = a % p, mb = b % p; ans += (b / p) * (ma + 1) + (a / p) * (mb + 1); if (ma > m) { ans += min(mb, m) + 1; ll tt = (m - ma + p) % p; if (tt <= mb) ans += mb - tt + 1; } else { ll t = (m - ma + p) % p; if (t <= mb) ans += min(m - t + 1, mb - t + 1); } return ans; } ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } int main() { int T; int kase = 1; scanf("%d", &T); while (T--) { scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &p, &m); ll ans = f(b, d) - f(b, c - 1) - f(a - 1, d) + f(a - 1, c - 1); ll sum = (b - a + 1) * (d - c + 1); ll g = gcd(ans, sum); printf("Case #%d: %lld/%lld ", kase++, ans / g, sum / g); } }
当然网上还有数形结合的方法,也是一种角度。
typedeflonglong ll; typedefunsignedlonglong ull; const ll MOD = 1e6 + 7; constint maxn = 3e5 +5; constdouble Inf = 10000.0; constdouble PI = acos(-1.0); usingnamespacestd; ll a, b, c, d, p, m; ll f(ll a, ll b) { if (a < 0 || b < 0) return0; ll ans = (a / p) * (b / p) * p; ll ma = a % p, mb = b % p; ans += (b / p) * (ma + 1) + (a / p) * (mb + 1); if (ma > m) { ans += min(mb, m) + 1; ll tt = (m - ma + p) % p; if (tt <= mb) ans += mb - tt + 1; } else { ll t = (m - ma + p) % p; if (t <= mb) ans += min(m - t + 1, mb - t + 1); } return ans; } ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } int main() { int T; int kase = 1; scanf("%d", &T); while (T--) { scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &p, &m); ll ans = f(b, d) - f(b, c - 1) - f(a - 1, d) + f(a - 1, c - 1); ll sum = (b - a + 1) * (d - c + 1); ll g = gcd(ans, sum); printf("Case #%d: %lld/%lld ", kase++, ans / g, sum / g); } }