CodeForces #368 div2 D Persistent Bookcase DFS

题目链接:D Persistent Bookcase

题意:有一个n*m的书架,开始是空的,现在有k种操作:

1 x y 这个位置如果没书,放书。

2 x y 这个位置如果有书,拿走。

3 x 反转这一行,即有书的位置拿走,没书的位置放上书。

4 x 返回到第x步操作之后的书架。

现在给出q个操作,询问每次操作之后书架上书的数量。

思路:

开始没有思路。后来被告知dfs。

【词不达意。参考:http://blog.csdn.net/zyjhtutu/article/details/52279494】

对于第i次操作的后的书架,要么是由第i-1次操作后的书架得到的,要么是返回到第x步。而,每一步得到的书架书的数量只有一种可能。

将操作看成边,当前的状态看作节点,建树。建树的规则是,如果进行的操作树1或者2或者3,那么就将操作后状态连接在当前状态后面

,如果操作是4,就将操作后的状态连接在要还原的状态后面。然后进行dfs,离线求解。dfs的巧妙之处在于,由于数据量比较大,不可

能将每次操作后的状态都记下来。其实,仔细想想,根本不需要记录所有的状态,只需要记录当前状态,然后dfs,回溯的时候将更改的

状态在改回来。这样,一边dfs就解决问题。时间复杂度为q*m。

附代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#define maxn 100100
using namespace std;

vector<int> nxt[maxn];
int ans[maxn];
int op[maxn], r[maxn], c[maxn];
bool vis[1010][1010]; //标记当前状态是否已经有书
int n, m;

void init() {
    ans[0] = 0;
    for (int i=1; i<=maxn; ++i) {
        nxt[i].clear();
    }
    memset(vis, 0, sizeof(vis));
}

void dfs(int x) {
    for (int i=0; i<nxt[x].size(); ++i) {
        int nxts = nxt[x][i]; // 从x出发能到达的所有状态
        //cout << nxts << " " << op[nxts] << "...\n";
        if (op[nxts] == 1) {
            if (vis[r[nxts]][c[nxts]]) { // 已经有书
                ans[nxts] = ans[x];
                dfs(nxts);
            }
            else {
                vis[r[nxts]][c[nxts]] = 1;
                ans[nxts] = ans[x] + 1;
                dfs(nxts);
                vis[r[nxts]][c[nxts]] = 0;
            }
        }
        else if (op[nxts] == 2) {
            if (vis[r[nxts]][c[nxts]] == 0) { // 没书
                ans[nxts] = ans[x];
                dfs(nxts);
            }
            else {
                vis[r[nxts]][c[nxts]] = 0;
                ans[nxts] = ans[x] - 1;
                dfs(nxts);
                vis[r[nxts]][c[nxts]] = 1;
            }
        }
        else if (op[nxts] == 3) {
            int cnt = 0;
            for (int j=1; j<=m; ++j) {
                if (vis[r[nxts]][j] == 0) {
                    cnt++;
                    vis[r[nxts]][j] = 1;
                }
                else {
                    cnt--;
                    vis[r[nxts]][j] = 0;
                }
            }
            ans[nxts] = ans[x] + cnt;
            dfs(nxts);
            for (int j=1; j<=m; ++j) {
                if (vis[r[nxts]][j] == 0) {
                    vis[r[nxts]][j] = 1;
                }
                else vis[r[nxts]][j] = 0;
            }
        }
        else if (op[nxts] == 4) {
            ans[nxts] = ans[x];
            dfs(nxts);
        }
    }
}

int main() {
   // freopen("in.cpp", "r", stdin);
    int q;
    while(~scanf("%d%d%d", &n, &m, &q)) {
        init();
        for (int i=1; i<=q; ++i) {
            scanf("%d", &op[i]);
            if (op[i] == 1 || op[i] == 2) {
                scanf("%d%d", &r[i], &c[i]);
                nxt[i-1].push_back(i);
            }
            else if (op[i] == 3) {
                scanf("%d", &r[i]);
                nxt[i-1].push_back(i);
            }
            else if (op[i] == 4) {
                scanf("%d", &r[i]);
                nxt[r[i]].push_back(i);
            }
        }

        dfs(0);
        for (int i=1; i<=q; ++i) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}

确实很巧妙。

时间: 2024-10-06 20:01:17

CodeForces #368 div2 D Persistent Bookcase DFS的相关文章

【Codeforces-707D】Persistent Bookcase DFS + 线段树

D. Persistent Bookcase Recently in school Alina has learned what are the persistent data structures: they are data structures that always preserves the previous version of itself and access to it when it is modified. After reaching home Alina decided

Codeforces #245(div2)

A:A. Points and Segments (easy) 题目看了n久,开始觉得尼玛这是div2的题目么,题目还标明了easy.. 意思是给你一n个点,m个区间,在n个点上放蓝球或者红球,然后让你找一种选择方案使得m个区间内的蓝球和红球数量之差不超过1. 开始想过用dfs,不过这只是div2的A题而已.. 然后想了下,直接输出010101序列不就可以么. 交了一发,发现要先排个序,再输出就可以了. AC代码: #include<iostream> #include<cstdio&g

Codeforces 6D Lizards and Basements 2 dfs+暴力

题目链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h> #include<queue> #include<string> #include<stdlib.h> #include<a

Codeforces 583 DIV2 Robot&#39;s Task 贪心

原题链接:http://codeforces.com/problemset/problem/583/B 题意: 就..要打开一个电脑,必须至少先打开其他若干电脑,每次转向有个花费,让你设计一个序列,使得总花费最小. 题解: 就傻傻的走就好..从左走到右,再走回来,更新序列和答案就好. 代码: #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #define MA

Codeforces #180 div2 C Parity Game

// Codeforces #180 div2 C Parity Game // // 这道题的题目意思就不解释了 // // 题目有那么一点难(对于我而言),不多说啦 // // 解题思路: // // 首先如果a串和b串相等,不多说直接YES // 如果b串全是0,直接YES // 注意到a串有一个性质,1的个数不会超过本身的加1. // a有个1的上限设为x,b有个1的个数设为y,则如果x < y // 那么直接NO. // // 现在一般情况下,就是模拟啦,找到a的后缀和b的前缀一样的

CodeForces 440C One-Based Arithmetic(递归,dfs)

A - One-Based Arithmetic Time Limit:500MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-08-21) Description Prof. Vasechkin wants to represent positive integer n as a sum of adden

Codeforces #246(div2)

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <ti

codeforces#327 div2

codeforces#327 div2 这场状态不好有点可惜,题目都不难,而且很好.. A题:水题. #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; typedef lo

codeforces#FF(div2) DZY Loves Sequences

n个数,可以任意改变其中一个数,求最长的上升子区间长度 思路:记录一个from[i]表示从位置i的数开始最长的上升区间长度 记录一个to[i]表示到位置i的数所能达到的最长上升区间长度 枚举要改变的数的位置i,此时能达到的长度为to[i - 1] + from[i + 1] + 1,取最大值 //#pragma comment(linker, "/STACK:102400000,102400000") //HEAD #include <cstdio> #include &l