zoukankan      html  css  js  c++  java
  • 【JZOJ6288】【NOIP提高组A】旋转子段

    题目大意

    给出一个(n)的排列,若(a[i]=i)(i)是一个固定点,现在你可以选一个区间翻转它,求翻转过后固定点的最大值(只能选一个区间,翻转一次)。

    分析

    对于一次交换((i,j))只会有三种情况:

    • (i)不在自己的位置上,交换后复位了。((j)同理)
    • (i)不在自己的位置上,交换后仍不在。
    • (i)原来在自己的位置上,交换后不在了。

    后两种用前缀和统计就行了,第一种的话,我们求出((i,a[i]))的中心,把((i,a[i]))挂在中心上,然后按长度排序,我们只用处理有元素复位的交换,其它交换用前缀和就能统计了。

    Code

    代码有点丑,见谅。

    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 100007;
    
    int n, ret = -0x3f3f3f3f, sum[N], a[N];
    
    struct note { int l, r, len; };
    vector<note> lis1[N], lis2[N];
    
    int cmp(note a, note b) { return a.len < b.len; }
    
    void doit1()
    {
    	for (int i = 1, p, q; i <= n; i++)
    	{
    		p = i, q = a[i];
    		if (p > q) swap(p, q);
    		if ((q - p) % 2 == 0) lis1[(p + q) / 2].push_back((note){p, q, q - p + 1});
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		sort(lis1[i].begin(), lis1[i].end(), cmp);
    		int sz = lis1[i].size(), s = 0;
    		for (int j = 0, lasl = i, lasr = i; j < sz; j++)
    		{
    			if (lis1[i][j].len == 1) { ret = max(ret, s); continue; }
    			if (lis1[i][j].l < lasl) s -= sum[lasl - 1] - sum[lis1[i][j].l];
    			if (lasr < lis1[i][j].r) s -= sum[lis1[i][j].r - 1] - sum[lasr];
    			if (j < sz - 1)
    			{
    				if (lis1[i][j].len == lis1[i][j + 1].len) s += 2, ++j;
    				else s += 1;
    			}
    			else s += 1;
    			lasl = lis1[i][j].l, lasr = lis1[i][j].r;
    			ret = max(ret, s);
    		}
    	}
    }
    
    void doit2()
    {
    	for (int i = 1, p, q; i <= n; i++)
    	{
    		p = i, q = a[i];
    		if (p > q) swap(p, q);
    		if ((q - p) % 2 == 1) lis2[(p + q) / 2].push_back((note){p, q, q - p + 1});
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		sort(lis2[i].begin(), lis2[i].end(), cmp);
    		int sz = lis2[i].size(), s = 0;
    		for (int j = 0, lasl = i + 1, lasr = i; j < sz; j++)
    		{
    			if (lis2[i][j].l < lasl) s -= sum[lasl - 1] - sum[lis2[i][j].l];
    			if (lasr < lis2[i][j].r) s -= sum[lis2[i][j].r - 1] - sum[lasr];
    			if (j < sz - 1)
    			{
    				if (lis2[i][j].len == lis2[i][j + 1].len) s += 2, ++j;
    				else s += 1;
    			}
    			else s += 1;
    			lasl = lis2[i][j].l, lasr = lis2[i][j].r;
    			ret = max(ret, s);
    		}
    	}
    }
    
    int main()
    {
    	//freopen("rotate.in", "r", stdin);
    	//freopen("rotate.out", "w", stdout);
    	//freopen("in", "r", stdin);
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + (i == a[i]);
    	doit1();
    	doit2();
    	printf("%d
    ", sum[n] + ret);
    	return 0;
    }
    
  • 相关阅读:
    四则运算试题生成,结对
    3 词频统计
    20190912-1 每周例行报告
    20190912-2 命令行
    每周例行报告
    作业要求 20190919-1 每周例行报告
    作业要求20190919-4 单元测试,结对
    作业要求 20190919-6 四则运算试题生成,结对
    作业要求20190919-5 代码规范,结对要求
    作业要求20190919-2 功能测试
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/11328305.html
Copyright © 2011-2022 走看看