• Codeforces 1169E DP


    题意:给你一个长度为n的序列,有q次询问,每次询问给出两个位置x和y(x < y),问是否可从x到达y?可达的定义是:如果存在一个序列(假设长度为k),其中p1 = x, pk = y,并且这个序列中a[pi] & a[p(i + 1)] != 0。

    思路:设dp[i][j]是从i位置及其之后的位置中,二进制位的第j位为1,并且可达的最靠前的位置,设last[j]是已经扫描过的数中第j位为1的最靠前的位置。我们考虑怎么求dp[i][j]。首先,如果a[i]的二进制位的第j位为1,那么dp[i][j] = i,而且i位置到last[j]一定是可达的,那么我们可以用dp[last[j]][k]来更新dp[i][k]。询问的时候,如果a[y]的第j位为1,并且dp[x][j] <= y, 那么就可达,否则不可达。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 300010;
    int dp[maxn][20], last[20];
    int a[maxn];
    int main() {
    	int n, T;
    	scanf("%d%d", &n, &T);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &a[i]);
    	}
    	for (int i = 0; i < 20; i++) {
    		last[i] = n + 1;
    		dp[n + 1][i] = n + 1;
    	}
    	for (int i = n; i >= 1; i--) {
    		for (int j = 0; j < 20; j++) {
    			dp[i][j] = n + 1;
    		}
    		for (int j = 0; j < 20; j++) {
    			if((a[i] >> j) & 1) {
    				for (int k = 0; k < 20; k++) {
    					dp[i][k] = min(dp[i][k], dp[last[j]][k]);
    				}
    				last[j] = i;
    				dp[i][j] = i;
    			}
    		}
    	}
    	while(T--) {
    		int x, y;
    		scanf("%d%d", &x, &y);
    		bool flag = 0;
    		for (int i = 0; i < 20; i++) {
    			if(((a[y] >> i) & 1) && dp[x][i] <= y) {
    				flag = 1;
    				break;
    			}
    		}
    		if(flag) printf("Shi
    ");
    		else printf("Fou
    ");
    	}
    }
    

      

  • 相关阅读:
    营山护照办理
    非北京人员 办理护照
    护照填写注意事项
    美国会议签证——我是正当理由去美国,我能支付(或有人为我支付)我在美国期间的所有费用,办完事我肯定回来, 邀请信,行程表这些材料齐全即可
    urllib2使用2
    python 异常
    python urllib和urllib2 区别
    python类继承
    gcc编译4个阶段
    Vim中如何全选并复制?
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10932964.html
Copyright © 2020-2023  润新知