zoukankan      html  css  js  c++  java
  • CF-1027-B. Curiosity Has No Limits

    CF-1027-B. Curiosity Has No Limits

    http://codeforces.com/contest/1072/problem/B

    题意:

    给定两组序列a,b,长度为n-1。求数列t使得

    a[i] = t[i]|t[i+1]

    b[i] = t[i]&t[i+1]

    其中( (0le a[i]le3) , (0 le b[i] le 3) )

    分析:

    • 刚看到这个题,感觉是dp,然后觉得范围只有0~3,可以分情况讨论,奈何写不出来转移方程于是dfs。然而写dfs也只是抓住每个情况不放,导致代码极丑无比。

    DP

    • t[i+1]t[i] a[i+1] b[i+1]共同决定,而a[i+1],b[i+1]i+1表示,只需要记录t[i]即可。
    • d[i+1][j]表示在 i+1阶段,t[i+1]j时,t[i]应该为多少。
    • 状态转移方程:d[i+1][l] = j( (l|j) == a[i] && (l&j) == b[i] )
    • 由于t[i]范围是0~3,所以先把d数组初始化为-1,表示都不能储存。并且由上述状态转移方程可以看出,我们把记忆化搜索路径已经存放到了d数组里面,最后倒序遍历存放到vecotr之后即可正序输出。
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 1;
    int a[N], b[N], dp[N][4],t[N];
    int main() {
        //加快cin输入,cout输出
        ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n;
        cin >> n;
        for (int i = 1; i < n; ++i)
            cin >> a[i];
        for (int j = 1; j < n; ++j) 
            cin >> b[j];
        memset(dp,-1,sizeof dp);
        for (int i = 0; i < 4; ++i)
            dp[1][i] = 0;
        /***核心***/
        for (int i = 1; i < n; ++i)
        	for (int j = 0; j <= 3; ++j)
    	    	if (dp[i][j] >= 0)
    	        	for (int l = 0; l <= 3; ++l)
    	        		if (a[i] == (j | l) && b[i] == (j & l))
    	            		dp[i + 1][l] = j;
        /***找到任意一组答案直接倒序遍历然后输出即可***/
        for (int i = 0; i < 4; ++i)
        {
            if (dp[n][i] >= 0) 
            {
    	        cout << "YES" << endl;
    	        vector <int> ans;
    	        int p = i, j = n;
    	        for (j = n; j > 0; --j) 
                {
    	            ans.push_back(p);
    	            p = dp[j][p];
    	        }
    	        for (j = ans.size() - 1; j >= 0; --j)
    	            cout << ans[j] << ' ';
    	        return 0;
            }
        }
        cout << "NO";
    }
    

    DFS

    • 每一层搜索,都要有上一层的t[i]来作为依据,不过我们把t[i]放到全局即可,不必放到dfs的参数中。参数只需记录搜索层数即可。
    int n,cnt,flag;
    void dfs(int p)
    {
    	if(flag)return;
    	if(p==n-1)
    	{
    		flag = 1;
    		printf("YES
    ");
    		for(int i=0;i<n;i++)
    			printf("%d ",t[i]);
    		return;
    	}
    	for(int i=0;i<=3;i++)
    		if((t[p]|i) == a[p]&&(t[p]&i)==b[p])
    		{
    			t[++p] = i;
    			dfs(p);
    		}
    }
    int main()
    {
    	while(~scanf("%d",&n))
    	{
    		cnt = 0;
    		flag = 0;
    		for(int i=0;i<n-1;i++)
    			scanf("%d",&a[i]);
    		for(int i=0;i<n-1;i++)
    			scanf("%d",&b[i]);
    		for(int i=0;i<=3;i++)
    		{
    			if(flag) break;
    			t[0] = i;
    			dfs(0);
    		}
    		if(flag == 0)printf("NO
    ");
    	}
    }
    

    总结:

    • 此题dfs代码好写,细节不用考虑太多。但效率不如dp。
    • 即便每一层情况很少,也不是一定分组考虑,有时直接遍历会更加方便。大神十分钟ac的题我却足足耗了四十分钟。
  • 相关阅读:
    石墨烯
    spring 安装
    orm 对象关系映射
    刷机问题
    环境必备
    spring 例子
    刷系统——黑屏问题
    android 文件下载
    c# 事件处理
    回忆测试广告理论
  • 原文地址:https://www.cnblogs.com/1625--H/p/9828915.html
Copyright © 2011-2022 走看看