题意:
求区间[l, r]中是7的倍数且不满足任一给定同余式的数的个数,
(0<l<r<108)
。
分析:
满足不同同余式的集合不同且可能有重叠,用容斥原理解决,联立同余式求解用中国剩余定理,因为pi都是素数,可以用互质版求解
**注意**crt中乘法会爆long long,写个快速乘。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int f[20];
LL a[20], m[20];
LL ex_gcd(LL a, LL b, LL &x, LL &y)
{
if(!b)
{
x = 1;
y = 0;
return a;
}
else
{
LL tmp = ex_gcd(b, a%b, y, x);
y -= a / b * x;
return tmp;
}
}
inline LL count(LL k, LL m, LL x)
{
return (m - k + x) / m;
}
LL mul(LL a, LL b, LL m)
{
LL ans = 0;
while(b)
{
if(b&1LL)
{
ans += a;
ans %= m;
}
a <<= 1;
a %= m;
b >>= 1;
}
return ans;
}
LL crt(int n, LL l, LL r)
{
LL M = 1;
for(int i = 0; i < n; i++)
if(f[i])
M *= m[i];
LL ans = 0;
for(int i = 0; i < n; i++)
if(f[i])
{
LL mi = M / m[i];
LL mf, tmp;
ex_gcd(mi, m[i], mf, tmp);
mf = (mf % m[i] + m[i]) % m[i];
ans += mul(mul(a[i], mi, M), mf, M);
ans = (ans % M + M) % M;
}
return count(ans, M, r) - count(ans, M, l-1);
}
int main(int argc, char const *argv[])
{
int t;
scanf("%d", &t);
for(int k = 1; k <= t; k++)
{
int n;
LL l, r;
scanf("%d%lld%lld", &n, &l, &r);
for(int i = 0; i < n; i++)
scanf("%lld%lld", &m[i], &a[i]);
m[n] = 7;
a[n] = 0;
f[n] = 1;
LL ans = 0;
int cc = 1 << n;
for(int i = 0; i < cc; i++)
{
int tmp = i, cnt = 0;
for(int j = 0; j < n; j++)
{
if(tmp&1)
{
cnt++;
f[j] = 1;
}
else
f[j] = 0;
tmp >>= 1;
}
if(cnt & 1)
ans -= crt(n+1, l, r);
else
ans += crt(n+1, l, r);
}
printf("Case #%d: %lld\n", k, ans);
}
return 0;
}