zoukankan      html  css  js  c++  java
  • 10.12T1 寻找性质

    Description

    ZYL有N张牌编号分别为1, 2,……,N。他把这N张牌打乱排成一排,然后他要做一次旋转使得旋转后固定点尽可能多。如果第i个位置的牌的编号为i,我们就称之为固定点。旋转可以被认为是将其中的一个子段旋转180度,这意味着子段的第一张牌和最后一张牌交换位置,以及第二张牌和倒数第二张牌交换位置,等等。写一个程序,找到旋转子段(子段长度可以为1)。

    Input

    第一行包含一个整数 N (1 ≤ N ≤500 000)。
    第二行有N个数,第i个数表示旋转之前第i个位置的牌的编号。

    Output

    找到固定点最多的旋转所选的子段,输出旋转之后固定点的个数。

    Sample Input

    4 3 2 1 4

    Sample Output

    4 在样例1中,只需要旋转的子段[3,2,1],将排列变成1 2 3 4,旋转后所有的牌都为固定点。答案为4。

    Hint

    【数据范围】
    30%的数据满足:N ≤ 500;
    60%的数据满足:N ≤ 5000;
    100%的数据满足:1 ≤ N ≤ 100 000。
     
     
     
     
    官方题解摆上:

    算法一:对于30%的数据: 直接枚举区间直接模拟,时间复杂度O(N3)。

    算法二:对于60%的数据:枚举旋转中心点,然后再枚举旋转的端点, 我们可以用O(n)的预处理求前缀和记录固定点,总时间复杂度O(N2)。

    算法三:对于100%的数据:假设有最优解为[i,j](i,j皆为下标,A[i],A[j]才是题目所要输出的答案)。if(A[i]!=j&&A[j]!=i),就是A[i]和A[j]经过旋转之后都没有成为不动点,那么[i+1,j-1]也是一个最优解(如果i+1>j-1,那么[1,1]也是最优解)。两端旋转之后如果都没成为不动点我们可以去掉两端,不停地去掉后得到最优解为[x,y]则有A[x]=y或者A[y]=x,或者x=y=1( [1,1]可以不参与讨论).

    因此最优解一定是[min(i,A[i]),max(i,A[i])](i=1,2,3......,n)。

    只需要枚举n个值就能找到最优解,由此找最优解问题变成了查询问题。假设i<=A[i],要查询的区间变成了三段[1,i-1]   [i, A[i] ]   [ A[i+1] ,n],固定点个数O(1)的时间查询。中间这一段 [i, A[i] ]经过了一次旋转,对于旋转后的固定点j有A[j]+j=A[i]+i且,而[j,A[j]]也是我们要考虑成为最优解的一个旋转,我们事先将这n种旋转按照轴心不同分类,每一类由旋转区间长度短到长排序。以上算法因为要排序所以复杂度为O(N log N)。

    简明一点就是[i,a[i]]一定是我们的答案区间,然后查询前后的区间没有翻转的个数可以前缀和水掉,至于中间的我们在读入的时候可以vector记录一下i+a[i]这个值有多少个位置是它,然后在枚举的时候就可以二分vector里面的位置就可以了(我tm强行多带了一个n导致50分,人傻自带一个n)

    code:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<algorithm>
     5 #define  N 1000005
     6 using namespace std;
     7 int a[N],s[N];
     8 vector<int>check[1000005];
     9 int main(){
    10     int n;
    11     cin>>n;
    12     for(int i=1;i<=n;i++){
    13         cin>>a[i];
    14         s[i]=s[i-1]+(a[i]==i?1:0);
    15         check[a[i]+i].push_back(i);
    16     }
    17     int max0=1;
    18     if(s[n]==n){
    19         cout<<n;
    20         return 0;
    21     }
    22     for(int i=1;i<=n;i++){
    23         if(a[i]==i)continue;
    24         int temp=0;
    25         temp+=s[min(i,a[i])-1]+s[n]-s[max(i,a[i])];
    26         int now=a[i]+i;
    27         int l=lower_bound(check[now].begin(),check[now].end(),min(i,a[i]))-check[now].begin();
    28         int r=upper_bound(check[now].begin(),check[now].end(),max(i,a[i]))-check[now].begin();
    29         max0=max(max0,r-l+temp);
    30     }
    31     cout<<max0;
    32     return 0;
    33 } 

    over

  • 相关阅读:
    学习源代码时的笨方法
    初步学习pg_control文件之十五
    初步学习pg_control文件之十四
    初步学习pg_control文件之十三
    fsync体会
    初步学习pg_control文件之十二
    初步学习pg_control文件之十一
    初步学习pg_control文件之十
    初步学习pg_control文件之九
    JS与原生OC/Swift相互调用总结
  • 原文地址:https://www.cnblogs.com/saionjisekai/p/9790370.html
Copyright © 2011-2022 走看看