JZOJ 6847. 【2020.11.03提高组模拟】通往强者之路(找规律+转化题意)
JZOJ 6847. 【2020.11.03提高组模拟】通往强者之路
题目大意
- 初始编号为 i ∈ [ 0 , n ) i\in[0,n) i∈[0,n)的格子上分别有 a i a_i ai砖,每次把第 i i i格的 x x x块砖拿走,放到 [ m a x ( i + 1 , n ) , i + x ] [max(i+1,n),i+x] [max(i+1,n),i+x]上,每格一块,多余的清空,
- q q q次询问,每次询问操作到格子 q i q_i qi时上面的砖块数量。
- n , q ≤ 1 0 5 n,q\leq 10^5 n,q≤105, q i ≤ 1 0 18 q_i\leq10^{18} qi≤1018, a i ∈ { n − 1 , n , n + 1 } a_i\in\{n-1,n,n+1\} ai∈{n−1,n,n+1}
题解
- 找规律或归纳法证明可以得到每个格子的答案都只有 { n − 1 , n , n + 1 } \{n-1,n,n+1\} {n−1,n,n+1}三种情况,不妨把它们分别看作是 { 0 , 1 , 2 } \{0,1,2\} {0,1,2}。
- 可以每 n n n个格子分成一段,若前 i − 1 i-1 i−1段的答案已经计算出来了,考虑如何计算第 i i i段的答案,
- 设 f i , j f_{i,j} fi,j表示第 i i i段第 j ( j ∈ [ 0 , n ) ) j(j\in[0,n)) j(j∈[0,n))个格子的答案,若 f i − 1 , j ≥ 1 f_{i-1,j}\geq1 fi−1,j≥1,那么 f i , j f_{i,j} fi,j可以加 1 1 1;若 f i − 1 , j − 1 = 2 f_{i-1,j-1}=2 fi−1,j−1=2,那么 f i , j f_{i,j} fi,j可以加 1 1 1。特别地,若 f i − 2 , n − 1 = 2 f_{i-2,n-1}=2 fi−2,n−1=2,则 f i , 0 f_{i,0} fi,0可以加 1 1 1。
- 再转化一下,相当于一段格子上叠有若干的砖块,从第 i i i段到第 i + 1 i+1 i+1段的过程相当于把所有第二层的砖块向右推一格,当右边没有砖块时,该砖块就会掉落并不再被推动。特别地,第 i i i段的最后一格砖块向右推直接推到第 i + 2 i+2 i+2段。
- 那么直接扫一遍求出每个 0 0 0的位置能不能被填上以及什么时候被填上,每个 2 2 2会不会掉落以及什么时候掉落、掉落在哪个位置,最后询问直接 O ( 1 ) O(1) O(1)处理。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define ll long long
int p[N], e[N], a[N], q[N];
int main() {
int tn;
scanf("%d", &tn);
while(tn--) {
int n, m, i; ll x;
scanf("%d%d", &n, &m);
q[0] = 0;
for(i = 0; i < n; i++) {
scanf("%d", &a[i]), a[i] -= n - 1;
e[i] = -1, p[i] = 0;
}
for(i = 0; i < n; i++) {
if(a[i] == 2) q[++q[0]] = i;
else if(!a[i] && q[0]) {
int t = q[q[0]];
e[t] = i, p[i] = i - t + 1;
q[0]--;
}
}
for(i = 0; i < n; i++) {
if(!a[i] && !p[i] && q[0]) {
int t = q[q[0]];
e[t] = i, p[i] = n - t + i + 2;
q[0]--;
}
}
for(i = 1; i <= m; i++) {
scanf("%lld", &x);
ll t = x / n + 1;
if(!a[x % n] && (!p[x % n] || p[x % n] > t)) printf("%d ", n - 1);
else {
int l = (t - 1) % (n + 1), y = x % n, z;
if(y - l == -1) printf("%d ", n);
else {
if(y - l >= 0) z = y - l; else z = y - l + n + 1;
if(a[z] == 2 && (e[z] == -1 || p[e[z]] > t || (p[e[y - l]] == t && e[y - l] > y))) printf("%d ", n + 1);
else printf("%d ", n);
}
}
}
printf("\n");
}
return 0;
}
哈哈哈哈哈哈哈哈哈哈

浙公网安备 33010602011771号