zoukankan      html  css  js  c++  java
  • Codeforces 1142B Lynyrd Skynyrd

    ---恢复内容开始---

    题意:给你一个排列p和数组a,有t组询问,每次询问一个区间的子序列中是否有p的一个循环排列。

    思路:以p = [3, 1, 2]举例, 我们扫描数组b,假设当前数字是1,那么我们找前面离现在最近的3的位置,然后连一条边。为什么只连最近的呢?比如[3,3,1,2]这种情况,1只需要和第二个3连就行了,因为连第一个3的这种情况已经被连第二个3的这种情况包含了。那么对于每个点,我们可以找到通过连的边走n - 1次所到的点,所有包含这个区间的询问区间都有一个合法的循环排列。但是直接暴力找n - 1次到的点会被卡成O(n^2)的,我们可以用倍增优化这个过程。之后,对于每个点,我们只需记录在它前面的点中满足走n  - 1次的点中最大的那一个就行了,因为这样相当于对于每个点,尽力压缩合法的区间。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 200010;
    int f[maxn][20], pre[maxn], a[maxn], b[maxn], last[maxn], p[maxn], res[maxn];
    int n, m, T, t;
    int solve(int x) {
    	int now = n - 1, ans = x;
    	for (int i = t; i >= 0; i--) {
    		if(p[i] <= now) {
    			ans = f[ans][i];
    			now -= p[i];
    		}
    	}
    	return ans;
    }
    int main() {
    	int l, r;
    	scanf("%d%d%d", &n, &m, &T);
    	t = (int)(log(n) / log(2)) + 1;
    	p[0] = 1;
    	for (int i = 1; i <= t;i++) {
    		p[i] = p[i - 1] * 2; 
    	}
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &a[i]);
    	}
    	for (int i = 2; i <= n; i++) {
    		pre[a[i]] = a[i - 1];
    	}
    	pre[a[1]] = a[n];
    	for (int i = 1; i <= m; i++) {
    		scanf("%d", &b[i]);
    		f[i][0] = last[pre[b[i]]];
    		for (int j = 1; j <= t; j++) {
    			f[i][j] = f[f[i][j - 1]][j - 1];
    		}
    		last[b[i]] = i;
    	}
    	int pos;
    	for (int i = 1; i <= m; i++) {
    		pos = solve(i);
    		res[i] = max(res[i - 1], pos);
    	}
    	while(T--) {
    		scanf("%d%d", &l, &r);
    		if(res[r] >= l) printf("1");
    		else printf("0");
    	}
    } 
    

      

    ---恢复内容结束---

  • 相关阅读:
    (转)PHP函数之error_reporting(E_ALL ^ E_NOTICE)详细说明
    Java 异步转同步 ListenableFuture in Guava
    makepy
    Eclipse安装Freemarker插件
    Windows下Go语言LiteIDE下载及安装
    Windows 平台下 Go 语言的安装和环境变量设置
    phpcms v9表单向导添加验证码
    mac下谷歌chrome浏览器的快捷键
    vscode的go插件安装
    golang查看文档
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10658118.html
Copyright © 2011-2022 走看看