给你 [l,r] 区间,问有多少数,是 7 的倍数,并且 mod 任何 p[i]≠a[i]
容斥 + 中国剩余定理 。我先吐槽下刘汝佳 CRT 板子,简直垃圾,太相信板子,半小时的题强行卡我3小时。。
分析一下题,再看看数据范围,一眼容斥。设 Pi,Pj 是两个素数。那么 mod 他们分别等于 ai,aj 的数在 [1,lcm(Pi,Pj)] 区间只有一个,我们用 n 减去这个数在加上 lcm 就把偏移差消掉了,然后直接除以 lcm 就是这个区间中符合当前枚举的条件的数量了。然后容斥去重。注意,不能直接传入总值除以7,我们需要把 (0,7) 丢进CRT里跑,这样才能把某些应该消掉的数消掉,否则要出错
板子啊,一定不要太相信板子!!!。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = (1 << 16) + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
int tot;
void exgcd(ll a, ll b, ll& d, ll& x, ll& y) {
if(!b) {d = a; x = 1; y = 0;}
else {exgcd(b, a%b, d, y, x); y -= x * (a / b);}
}
ll inv(ll a, ll n) {
ll d, x, y;
exgcd(a, n, d, x, y);
return d == 1 ? (x + n) % n : -1;
}
ll mul(ll a, ll b, ll M) {
ll ret = 0;
while(b) {
if(b & 1) ret = (ret + a) % M;
a = a * 2 % M;
b >>= 1;
}
return ret;
}
ll CRT(ll a[], ll m[], ll n) {
ll M = 1;
ll ans = 0;
for(int i = 1; i <= n; i++)
M *= m[i];
for(int i = 1; i <= n; i++) {
ll Mi = M / m[i];
ll x, y, d;
exgcd(Mi, m[i], d, x, y);
ans = (ans + mul(x, mul(a[i], Mi, M), M)) % M;
}
if(ans < 0) ans += M;
return ans;
}
ll p[22];
ll a[22];
ll A[22], m[22], all;
ll calc(ll n) {
int state = 0;
ll res = 0;
for(state = 1; state < 1 << tot; state++) {
all = 0;
ll di = 7;
int op = __builtin_popcount(state);
A[++all] = 0;
m[all] = 7;
for(int i = 0; i < tot; i++) {
if(state >> i & 1) {
di *= p[i];
A[++all] = a[i];
m[all] = p[i];
}
}
ll kk = CRT(A, m, all);
ll tmp = (n - kk + di) / di;
if(op & 1) res += tmp;
else res -= tmp;
}
return n / 7 - res;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
int T;
scanf("%d", &T);
int cas = 0;
while(T--) {
ll n, x, y;
scanf("%lld%lld%lld", &n, &x, &y);
tot = n;
for(int i = 0; i < n; i++) {
scanf("%lld%lld", &p[i], &a[i]);
}
if(n == 0) printf("Case #%d: %lld\n", ++cas, y / 7 - (x - 1) / 7);
else printf("Case #%d: %lld\n", ++cas, calc(y) - calc((x - 1)));
}
return 0;
}