ACM/ICPC 之 中国剩余定理+容斥原理(HDU5768)
二进制枚举+容斥原理+中国剩余定理
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define MAXN 20 typedef long long LL; int n; int s[MAXN]; LL a[MAXN], m[MAXN]; //a是余数,m是除数 LL extented_gcd(LL a,LL b, LL &x, LL &y) //扩展欧几里得 { if(a == 0 && b == 0) return -1; if(b == 0){ x = 1; y = 0; return a; } LL d = extented_gcd(b, a%b, y, x); y -= a/b*x; return d; } LL mult(LL a, LL k, LL m){ //快速乘法 LL res = 0; while(k){ if(k & 1LL) res = (res + a) % m; k >>= 1; a = (a << 1) % m; } return res; } //x = ai(mod mi) mi之间互素 //M = m1 * m2 * ... * mi //Mi'*Mi = 1 (mod mi) Mi = M/mi //x = sigma(ai * Mi * M') % M LL CRT(LL l, LL r) //中国剩余定理 { LL M = 1, ans = 0; for (int i = 0; i <= n; ++i) if(s[i]) M *= m[i]; for(int i = 0;i <= n;i++) { if(s[i]){ LL Mi = M/m[i]; LL x,y; extented_gcd(Mi, m[i], x,y); //求Mi*x=1(mod m[i]) x = (x%m[i] + m[i]) % m[i]; ans = (ans+mult(a[i]*Mi % M, x, M)) % M; //计算最小解 } } return (r+M-ans)/M - (l-1+M-ans)/M; //计算[l,r]间解的个数 } int main() { //freopen("in", "r", stdin); int T, cas = 0; scanf("%d", &T); while(T--){ LL l, r; scanf("%d%lld%lld", &n, &l, &r); memset(s, 0, sizeof(s)); m[n] = 7; a[n] = 0; s[n] = 1; for(int i = 0;i < n;i++) scanf("%lld%lld", &m[i], &a[i]); LL ans = 0; int all = 1 << n; for(int i = 0;i < all;i++){ //二进制枚举同余方程 int t = i, k = 0; for(int j = 0;j < n;j++){ s[j] = t & 1; t >>= 1; k += s[j]; //计算同余方程个数 } k = k & 1 ? -1 : 1;//容斥定理-奇减偶加 ans += 1LL * k * CRT(l, r); } printf("Case #%d: %lld\n", ++cas, ans); } return 0; }
他坐在湖边,望向天空,她坐在对岸,盯着湖面