前言:你怎么知道我这场拿了一血,然后各种犯病代码到结束。
题意: 假设有一个AC自动机(不是这个 AC自动机 ),约定写代码大于x行就算AC,每次AC以后代码会自动清空。
有T次操作数,并且现在有以下两种操作:
1、写k行代码。
2、查询目前AC数量。
数据范围 $$1 \leq x \leq 10^{12},1\leq T\leq10^6$$
$$1 \leq k \leq 10^{12}$$
题解:模拟 按题意。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void JiuCherish () { i64 n,t; std::cin >> n >> t; i64 now = 0 ; i64 ans = 0 ; while (t--) { int op; std::cin >> op; if (now > n) { ans += 1 ; now = 0 ; } if (op == 1 ) { i64 w = 0 ; std::cin >> w; now += w; } else { std::cout << ans << endl; } } }
题意: 我们需要计算两个相交平面之间的二面角。给定四个点 A,B,C,D的三维坐标,我们需要找到二面角 A−BC−D 的度数。
数据范围 每个点坐标都满足:
$$-10^4 \leq x,y,z \leq 10^{4}$$
保证四个坐标不重合。
题解:计算几何 先算向量,再算法向量,计算二面角的余弦值,最后确认角度。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 struct Vector3D { double x, y, z; Vector3D (double x = 0 , double y = 0 , double z = 0 ) : x (x), y (y), z (z) {} Vector3D operator -(const Vector3D& v) const { return Vector3D (x - v.x, y - v.y, z - v.z); } double dot (const Vector3D& v) const { return x * v.x + y * v.y + z * v.z; } Vector3D cross (const Vector3D& v) const { return Vector3D (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } double norm () const { return sqrt (x * x + y * y + z * z); } }; void JiuCherish () { Vector3D A, B, C, D; cin >> A.x >> A.y >> A.z; cin >> B.x >> B.y >> B.z; cin >> C.x >> C.y >> C.z; cin >> D.x >> D.y >> D.z; Vector3D AB = B - A; Vector3D BC = C - B; Vector3D CD = D - C; Vector3D n_ABC = AB.cross (BC); Vector3D n_BCD = BC.cross (CD); double cos_angle = (n_ABC.dot (n_BCD) / (n_ABC.norm () * n_BCD.norm ())); double angle = acos (cos_angle) * 180 / M_PI; int int_angle = static_cast <int >(angle); if (fmod (angle, 1 ) >= 0.5 ) { int_angle++; } std::cout << int_angle << endl; }
题意: Alice和Bob在玩一个游戏
游戏开始时有 n 颗钻石,假设当前钻石数为 x,那么每位玩家在每个回合可以选择以下三种操作之一:
如果 5 能整除 x 并且 x≥5,那么他/她可以选择移除 5 颗钻石。
如果 2 能整除 x 并且 x≥2,那么他/她可以选择移除 2 颗钻石。
如果 x≥1,那么他/她可以选择移除 1 颗钻石。
Alice先手,并且双方用最优策略进行游戏,问最终谁会赢。
数据范围 $$1 \leq T \leq 10^{4}$$
$$1 \leq n \leq 10^{9}$$
题解:博弈,Nim 通过手玩 < 10的数可以发现:
1 2 3 4 5 6 7 8 9 i:1 Alice i:2 Alice i:3 Bob i:4 Alice i:5 Alice i:6 Bob i:7 Alice i:8 Alice i:9 Bob
有以上规律。
以6为例,Alice先手,那么一定有他有两种操作:第一种是 -1,那么钻石到了5,由于5 % 5==0所以Bob拿走五个钻石就能获胜,第二种是 6 % 2 == 0,因此拿走2个,也就是来到4,由于有了前五种情况,当钻石数到了4并且是Alice的时候,此时的Alice是必胜的状态,但是此时是Bob的回合,Bob可以通过Alice在四个钻石时候获胜手段再次获胜,因此6是Alice的必败态。
通过以上规律我们进行Nim打表得出下面规律:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 i:1 Alice i:2 Alice i:3 Bob i:4 Alice i:5 Alice i:6 Bob i:7 Alice i:8 Alice i:9 Bob i:10 Alice i:11 Bob i:12 Alice i:13 Bob i:14 Alice i:15 Bob i:16 Alice i:17 Bob i:18 Alice i:19 Bob i:20 Alice i:21 Bob i:22 Alice i:23 Bob i:24 Alice i:25 Bob i:26 Alice //篇幅有限
Nim打表代码:
1 2 3 4 5 6 7 8 9 10 11 12 unordered_map<int , int > memo; int nim_value (int n) { if (n == 0 ) return 0 ; if (memo.count (n)) return memo[n]; int result = 0 ; if (n >= 5 && n % 5 == 0 ) result = nim_value (n - 5 ) ^ 1 ; if (n >= 2 && n % 2 == 0 ) result = max (result, nim_value (n - 2 ) ^ 1 ); result = max (result, nim_value (n - 1 ) ^ 1 ); memo[n] = result; return result; }
结合以上规律得到最终代码
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void JiuCherish () { int n; cin >> n; if (n <= 9 ) { if (n % 3 == 0 ) { std::cout << "Bob" << endl; } else { std::cout << "Alice" << endl; } } else { if (n & 1 ) { std::cout << "Bob" << endl; } else { std::cout << "Alice" << endl; } } }
题意: rubbidows 系统将在第 ti秒执行操作 pi(pi∈{1,2}),其中操作 1 是自动按 Home 键,操作 2 是自动按 End 键。
输入的起始时间是第 1 秒,每个字符的输入需要 1 秒。操作必须在字符输入后执行。换句话说,如果 ti=x,那么只有在 rubbidows 系统输入第 x 个字符后,系统才会自动按 Home 或 End 键。
由于 Yuangq 把所有的钱都花在了买礼物上,他没有足够的钱购买官方的 Rubbish&Windows 版本,所以 Yuangq 决定以不同的方式输入。他想知道他必须以什么顺序输入才能正确输入字符串。
关于 Home 和 End 键:
Home 键将光标移动到编辑或非编辑窗口的第一行的第一个单词。
End 键正好相反,光标将被定位在最后。
数据范围 $$0 \leq |S| \leq 2 \times10^6$$
$$1 \leq n \leq 5 \times 10^5$$
$$ 0 < t_i < |S|$$
$$p_i = {1 or 2}$$
题解:模拟,前缀和 有点复杂的模拟
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 struct P { int time,op,len; }a[MAXN]; void JiuCherish () { std::string s; std::cin >> s; int n; std::cin >> n; bool end = false ; bool home = false ; bool ok = false ; a[0 ].time = 0 ; a[0 ].op = 1 ; for (int i=1 ;i<=n;i++) { std::cin >> a[i].time >> a[i].op; } for (int i=0 ;i<n;i++) a[i].len = a[i + 1 ].time - a[i].time; a[n].len = s.length () - a[n].time; std::sort (a,a + n + 1 ,[&](P a,P b){ if (a.op != b.op)return a.op < b.op; else if (a.op == 1 ) { return a.time > b.time; } else { return a.time < b.time; } }); std::vector<std::pair<int ,char >> ans; for (int i=0 ;i<=n;i++) { for (int j=1 ;j<=a[i].len;j++) { ans.pb ({a[i].time - 1 + j,'a' }); } } for (int i=0 ;i<s.length ();i++) { ans[i].se = s[i]; } std::sort (ans.begin (),ans.end (),[&](std::pair<int ,int > a,std::pair<int ,int > b){ return a.fi < b.fi; }); for (auto [x,y] : ans) std::cout << y; }
题意: 有四个专业的学生,人数分别为a,b,c,d ,现在他们需要到相应的教室去上课,问最少需要安排几个教室?
教室需要满足如下情况:
1、每个教室只能容纳30人。
2、每个教室只能全都是相同专业的学生。
数据范围 $$1\leq T \leq10^4$$
$$1 \leq a,b,c,d \leq 10^{9}$$
题解:模拟 每个专业人数除30再看看%30 为不为0就好了。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void JiuCherish () { int a,b,c,d; i64 ans = 0 ; std::cin >> a >> b >> c >> d; ans += a / 30 ; ans += b / 30 ; ans += c / 30 ; ans += d / 30 ; ans += (a % 30 != 0 ); ans += (b % 30 != 0 ); ans += (c % 30 != 0 ); ans += (d % 30 != 0 ); std::cout << ans << endl; }
题意: 旅行者刚偷走了 Furina 最喜欢的甜点,现在 Furina 正在疯狂地在整个 Fontaine 寻找这个该死的旅行者!
Fontaine 是一个由 n 行和 m列的网格组成的国家,行号为 1,2,3,…,n,列号为 1,2,3,…,m。我们可怜的旅行者现在在坐标 (1,1)的网格上,时间是 1,他期望到达坐标 (n,m) 的网格,以便从 Fontaine 逃脱。在每个时刻,旅行者只能向下或向右移动任意数量的网格。
为了抓住旅行者,Furina 召集了 q 名检查员,他们计划在时间 ti到达坐标 (xi,yi)来抓住旅行者,只要旅行者在 ti时到达、经过或离开 (xi,yi),他就会被抓住!此外,Furina 将在时间 k 关闭 Fontaine 的大门,如果旅行者在此之前没有逃脱,他就永远无法逃脱!
然而,旅行者是一个数学爱好者,所以无论在什么危机情况下,只要没有被抓住,他就想找出他最快的逃脱方案,以及总共有多少种方案。
注释:不同的旅行方案是根据逃跑的方向和距离来区分的,不需要在每个时刻都是相同的。例如,即使路线相同,执行方式的不同仍然会导致不同的方案。
数据范围 $$2\leq n,m \leq 500$$
$$1 \leq q,k \leq 100$$
$$1 \leq x_i \leq n,1\leq y_i\leq m,1 \leq t_i \leq k$$
题解:前缀和优化dp 约定 dp({i,j,k}) 表示 到 坐标(i,j)所花的时间为k 的方案数,那么就有
$$dp[i][j][k] = 左边所有dp[点][k - 1]$$
$$dp[i][j][k] = 上面所有dp[点][k-1]$$
转移过来的。
由于暴力枚举 n * m * k * (m or n)会超时因此考虑将行走过的路径进行前缀和进行优化。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 void JiuCherish () { int n, m, q, k; cin >> n >> m >> q >> k; memset (t, 0x3f , sizeof (t)); while (q--) { int x, y, z; cin >> x >> y >> z; t[x][y] = min (t[x][y], z); } int ret = 0 , mn = 0x3f3f3f3f ; memset (f, 0 , sizeof (f)); f[1 ][1 ] = 1 ; for (int u = 1 ; u <= k; u++) { for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { if (t[i][j] <= u) r[i][j] = 0 ; else r[i][j] = (r[i][j - 1 ] + f[i][j]) % mod; } } for (int i = 1 ; i <= m; i++) { bool flag = true ; for (int j = 1 ; j <= n; j++) { if (t[j][i] <= u) c[i][j] = 0 ; else c[i][j] = (c[i][j - 1 ] + f[j][i]) % mod; } } for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { if (t[i][j] <= u) f[i][j] = 0 ; else f[i][j] = (r[i][j - 1 ] + c[j][i - 1 ]) % mod; } } ret = (ret + f[n][m]) % mod; if (f[n][m]) mn = min (mn, u); } if (!ret) cout << -1 << '\n' ; else cout << ret << ' ' << mn << '\n' ; }
题意: 建造了这样一个 n
层的Waylon三角墙,之后,Yuangq拿了数以百万计的同样大小的绿色卡片来覆盖墙壁,每张卡片正好覆盖2块。因为一旦绿色卡片被撕开就会看起来很糟糕,他希望没有一张绿色卡片被撕开,所以所有的绿色卡片必须正好覆盖2块。
由于Yuangq对数学有着非凡的热情,他也希望能够计算出他可以给Waylon三角墙涂上多少种不同的颜色。所以,你的任务是为他计算出来!
数据范围 $$1 \leq T \leq 10^3$$
$$1 \leq n \leq 10^5$$
题解:数学 如果考虑单层涂色,那么可以延续前一层的涂色方式。
如果考虑双层涂色,那么可以将i与i-1组合起来,因此有:
$$f[i] = f[i - 1] + f[i - 2]$$
从第1层到第i层的涂色方式的方案数为
$$g[i] = g[i - 1] * f[i]$$
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void init () { f[0 ] = 1 ;g[0 ] = 1 ; f[1 ] = 2 ;g[1 ] = 2 ; for (int i=2 ;i<=MAXN;i++) { f[i] = (f[i - 1 ] + f[i - 2 ]) % mod; g[i] = f[i] * g[i - 1 ]; g[i] %= mod; } } void JiuCherish () { int n; std::cin >> n; std::cout << g[n - 1 ] % mod << endl; }
题意: 首先我们定义一个大小为n,并且非递减没有负数 的数组 a称为优秀数组,同时规定 sum为a整个数组的异或值。问你是否能构造出这样的优秀数组同时满足 sum 是 n 的因子。
数据范围 $$1\leq T \leq10^4$$
$$1 \leq n \leq 2 \cdot 10^5$$
并且保证
$$n * T < 2 \cdot 10^5$$
题解:模拟 考虑到 1是所有数的因子,并且 我们知道 (a ^ a) = 0 和 (0 ^ a) = a
所以构造 000….1 或者 011…1(注意奇偶)即可。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void JiuCherish(){ int n; std::cin >> n; if(n & 1) { for(int i=0;i<n;i++) { std::cout << 1 << ' '; } std::cout << endl; } else { std::cout << 0 << ' '; for(int i=1;i<n;i++) { std::cout << 1 << ' '; } std::cout << endl; } }