写了一晚上的题
Tips(写在前面)
由于此题为分类讨论题,故此文章与写代码同步进行并同步更新。
为了方便描述,下称:
引入个重要结论(不打红心):
任意在
5\sim 5\times k_i 之间的数均可被两次数字镖(一次2 镖一次3 镖)打出来,特别的,5\times k_i-1 不行,且5\times k + 1\sim 6\times k 中的3 的倍数可以被打出来(理论上2\sim 4 也可以被打出来,但便于表述准确不将二者混为一谈)。
故无解的情况就比较简单了。
简单证明:
-
方法一:豆豆大法,即根据同余拼出需要的余数
x\equiv p\pmod 5 。其中x 为需要拼的数。 -
方法二:分类讨论
5 种模数的情况,均可表示为2\times x+3\times y 的形式,且x,y 满足x,y\leq k 。这里自行证明或参考其他题解。
只提一下为什么
同上,
All cases
不一定是对的,根据个人理解,或许与其他题解有出入。
但要注意很重要的一点:不一定要用满
由于第三镖较特殊,故将前两镖与第三镖分开讨论。
首先判断情况总数。第三镖显然只有大红心(小红心两倍)或者
而前两镖要讨论红心的个数,位置无所谓。这里假定有红心就先打(即若红心只有一个则打到第一镖)。
故讨论红心个数
考虑两两组合进行讨论,于是共有
这里假定前两镖红心个数为
-
- 在 $1\sim 5\times k$ 之间,融合前两镖随便打出 $3$ 镖再配合第三镖当做结论中的 $2$ 镖即可。 - 反之,要取前两镖中的其中一个 $3$ 镖与第三镖融合,在配合前两镖中的另一镖用结论。
int lt = x - 5 * k;//一次结论后还需要打的,也即 x - 融合镖打的
//case 1
if(2 <= x && lt + 2 <= 2 * k) res = 1;
if(2 <= x && lt + 2 <= 3 * k) res = 1;
//case 2
if(lt % 2 == 0 && (2 <= lt && lt <= 2 * k)) res = 1;
if(lt % 3 == 0 && (0 <= lt && lt <= 3 * k)) res = 1;
-
```cpp x -= 2 * m[i]; if(2 <= x && x <= 5 * k && x != 5 * k - 1) res = 1; if(0 <= x && x <= 6 * k && x % 3 == 0) res = 1; ``` -
```cpp x -= 2 * m[i]; if(2 <= x && x <= 5 * k && x != 5 * k - 1) res = 1; ``` -
```cpp int f0 = x - 2 * m[i], f1 = x - 3 * m[i], f2 = x - 4 * m[i];//f0 即为特殊处理(只打两镖) if(f0 >= 0 && ((f0 % 1 == 0 && f0 <= k * 1) || (f0 % 2 == 0 && f0 <= k * 2) || (f0 % 3 == 0 && f0 <= k * 3))) res = 1; if(f1 >= 0 && ((f1 % 1 == 0 && f1 <= k * 1) || (f1 % 2 == 0 && f1 <= k * 2) || (f1 % 3 == 0 && f1 <= k * 3))) res = 1; if(f2 >= 0 && ((f2 % 1 == 0 && f2 <= k * 1) || (f2 % 2 == 0 && f2 <= k * 2) || (f2 % 3 == 0 && f2 <= k * 3))) res = 1; ``` -
```cpp int f[5]; rep(j, 0, 4) f[j] = x - j * m[i]; rep(j, 0, 4) { if(f[j] % 2 == 0 && (1 <= f[j] / 2 && f[j] / 2 <= k)) { res = 1; break; } } ``` -
```cpp int F[7]; rep(j, 2, 6) F[j] = x - j * m[i]; rep(j, 2, 6) { if(F[j] == 0) { res = 1; break; } } ```
Code
#include <bits/stdc++.h>
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define int long long
#define pb push_back
using namespace std;
const int N = 1e6 + 5;
int n, k[N], m[N], x[N];
int a, b, c, d, ans;
void init() {
cin >> a >> b >> c >> d >> k[1];
rep(i, 2, n) k[i] = (a * k[i - 1] % d * k[i - 1] % d + b * k[i - 1] % d + c) % d + 20;
cin >> a >> b >> c >> d >> m[1];
rep(i, 2, n) m[i] = (a * m[i - 1] % d * m[i - 1] % d + b * m[i - 1] % d + c) % d + 20;
cin >> a >> b >> c >> d >> x[1];
rep(i, 2, n) x[i] = (a * x[i - 1] % d * x[i - 1] % d + b * x[i - 1] % d + c) % d + 20;
}
bool check(int i, int x, string id) {
int res = 0;
if(id == "00") {
int lt = x - 5 * k[i];//一次结论后还需要打的,也即 x - 融合镖打的
//case 1
if(2 <= x && lt + 2 <= 2 * k[i]) res = 1;
if(2 <= x && lt + 2 <= 3 * k[i]) res = 1;
//case 2
if(lt % 2 == 0 && (2 <= lt && lt <= 2 * k[i])) res = 1;
if(lt % 3 == 0 && (0 <= lt && lt <= 3 * k[i])) res = 1;
}
if(id == "01") {
x -= 2 * m[i];
if(0 <= x && x <= 5 * k[i] && x != 5 * k[i] - 1) res = 1;
if(0 <= x && x <= 6 * k[i] && x % 3 == 0) res = 1;
}
if(id == "10") {
int f1 = x - 0 * m[i],
f2 = x - 1 * m[i],
f3 = x - 2 * m[i];
if(2 <= f1 && f1 <= 5 * k[i] && f1 != 5 * k[i] - 1) res = 1;
if(2 <= f2 && f2 <= 5 * k[i] && f2 != 5 * k[i] - 1) res = 1;
if(2 <= f3 && f3 <= 5 * k[i] && f3 != 5 * k[i] - 1) res = 1;
}
if(id == "11") {
int f0 = x - 2 * m[i],
f1 = x - 3 * m[i],
f2 = x - 4 * m[i];//f0 即为特殊处理(只打两镖)
if(f0 >= 0 && ((f0 % 1 == 0 && f0 <= k[i] * 1) || (f0 % 2 == 0 && f0 <= k[i] * 2) || (f0 % 3 == 0 && f0 <= k[i] * 3))) res = 1;
if(f1 >= 0 && ((f1 % 1 == 0 && f1 <= k[i] * 1) || (f1 % 2 == 0 && f1 <= k[i] * 2) || (f1 % 3 == 0 && f1 <= k[i] * 3))) res = 1;
if(f2 >= 0 && ((f2 % 1 == 0 && f2 <= k[i] * 1) || (f2 % 2 == 0 && f2 <= k[i] * 2) || (f2 % 3 == 0 && f2 <= k[i] * 3))) res = 1;
}
if(id == "20") {
int f[5];
rep(j, 0, 4) f[j] = x - j * m[i];
rep(j, 0, 4) {
if(f[j] % 2 == 0 && (1 <= f[j] / 2 && f[j] / 2 <= k[i])) {
res = 1;
break;
}
}
}
if(id == "21") {
int F[7];
rep(j, 2, 6) F[j] = x - j * m[i];
rep(j, 2, 6) {
if(F[j] == 0) {
res = 1;
break;
}
}
}
return res;
}
signed main () {
ios::sync_with_stdio(0);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
init();
rep(i, 1, n) {
bool f = 0;
if(check(i, x[i], "00")) f = 1;
if(check(i, x[i], "01")) f = 1;
if(check(i, x[i], "10")) f = 1;
if(check(i, x[i], "11")) f = 1;
if(check(i, x[i], "20")) f = 1;
if(check(i, x[i], "21")) f = 1;
ans += f;
}
cout << ans;
return 0;
}