• JZOJ 6847. 【2020.11.03提高组模拟】通往强者之路(找规律+转化题意)


    JZOJ 6847. 【2020.11.03提高组模拟】通往强者之路

    题目大意

    • 初始编号为 i ∈ [ 0 , n ) iin[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,qleq 10^5 n,q105 q i ≤ 1 0 18 q_ileq10^{18} qi1018 a i ∈ { n − 1 , n , n + 1 } a_iin{n-1,n,n+1} ai{n1,n,n+1}

    题解

    • 找规律或归纳法证明可以得到每个格子的答案都只有 { n − 1 , n , n + 1 } {n-1,n,n+1} {n1,n,n+1}三种情况,不妨把它们分别看作是 { 0 , 1 , 2 } {0,1,2} {0,1,2}
    • 可以每 n n n个格子分成一段,若前 i − 1 i-1 i1段的答案已经计算出来了,考虑如何计算第 i i i段的答案,
    • f i , j f_{i,j} fi,j表示第 i i i段第 j ( j ∈ [ 0 , n ) ) j(jin[0,n)) j(j[0,n))个格子的答案,若 f i − 1 , j ≥ 1 f_{i-1,j}geq1 fi1,j1,那么 f i , j f_{i,j} fi,j可以加 1 1 1;若 f i − 1 , j − 1 = 2 f_{i-1,j-1}=2 fi1,j1=2,那么 f i , j f_{i,j} fi,j可以加 1 1 1。特别地,若 f i − 2 , n − 1 = 2 f_{i-2,n-1}=2 fi2,n1=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("
    ");
    	}
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    vim插件:显示树形目录插件NERDTree安装 和 使用【转】
    CMake 入门实战【转】
    在 linux 下使用 CMake 构建应用程序【转】
    Buildroot构建指南——根文件系统(Rootfs)【转】
    Buildroot构建指南--快速上手与实用技巧【转】
    Vim升华之树形目录插件NERDTree安装图解【转】
    【转】Android端与Android端利用WIFI进行FTP通信
    【转】Android 服务器之SFTP服务器上传下载功能 -- 不错
    【转】session setup failed: NT_STATUS_LOGON_FAILURE -- 不错
    【转】Mac OS X开机启动Path had bad permissions错误解决方案
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279515.html
Copyright © 2020-2023  润新知