Link
题意:给你一个n, x, y, 然后后面n行每行一个质数 p[i], 和一个余数 m[i]让你求满足在 x~y之间满足能被7整除且不能满足任何一个 方程组 num % p[i] == m[i], p[i]是质数。
思路:由题意想到要用中国剩余定理, 但题目要求的是 x%p[i] != m[i], 所以利用容斥定理
S
−
A
1
∪
A
2
∪
A
3
.
.
.
S−A_1∪A_2∪A_3...
S−A1∪A2∪A3...
S即为x~y中能被7整除的数
A
1
∪
A
2
∪
A
3
.
.
.
A_1∪A_2∪A_3...
A1∪A2∪A3... 即为满足x % p[i] == m[i]的集合
关键点在于去重, 我们可以发现假设只有两个方程组
容斥原理
总结一下,可以发现计算规律:把所有集合相加,同时减去所有偶数重复,加上所有奇数重复。简单来记忆就是减偶加奇。
对于本题而言,就是在满足x % 7 == 0 的基础上再实现容斥,先把所有单个方程满足的解的个数相加, 再减去所有两个两个方程组成一起的解, 然后加上所有三个三个一起组成的解,实现偶减奇加
再利用二进制枚举即可
细节见于代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6 + 10;
ll a[N], m[N];
void exgcd(ll a, ll b, ll &d, ll &x, ll &y)
{
if(b == 0)
{
x = 1, y = 0, d = a;
}
else
{
exgcd(b, a % b, d, y, x);
y -= (a / b) * x;
}
}
ll fuml(ll a, ll b, ll mod)
{
ll ans = 0;
while(b)
{
if(b & 1) ans = (ans + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return ans;
}
ll exCRT(int n)
{
for(int i = 2; i <= n; i ++)
{
ll d, x, y;
exgcd(m[1], m[i], d, x, y);
ll t = m[i] / d;
ll c = ((a[i] - a[1]) % m[i] + m[i]) % m[i];
x = fuml(x, c / d, t);
a[1] += x * m[1];
m[1] *= t;
a[1] = (a[1] % m[1]) % m[1];
}
return (a[1] % m[1] + m[1]) % m[1];
}
ll p[N], a1[N];
int main()
{
ll t;
scanf("%lld", &t);
for(int k = 1; k <= t; k ++)
{
ll n, x, y;
scanf("%lld%lld%lld", &n, &x, &y);
for(int i = 0; i < n; i ++)
{
scanf("%lld%lld", &p[i], &a1[i]);
}
ll sum = 0;
for(int g = 0; g < (1 << n); g ++)
{
int cnt = 0;
ll gbs = 7;
m[++cnt] = 7, a[cnt] = 0;
for(int r = 0; r < n; r ++)
{
if(g & (1 << r))
{
m[++cnt] = p[r], a[cnt] = a1[r], gbs *= p[r];
}
}
ll ps = exCRT(cnt);
ll c = 0, d = 0;
if(x - 1 - ps >= 0) c = (x - 1 - ps) / gbs + 1;
if(y >= ps) d = (y - ps) / gbs + 1;
ll ans = 0;
if(c < d) ans = d - c;
if((cnt - 1) & 1) sum -= ans;
else sum += ans;
}
printf("Case #%d: %I64d\n", k, sum);
}
}