旋转子段(性质分析)

Posted wwb123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了旋转子段(性质分析)相关的知识,希望对你有一定的参考价值。

60分

n^2的暴力很显然嘛........

枚举每个固定点,用个指针向区间两边扫

技术图片
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<string>
 7 #include<map>
 8 #include<vector>
 9 #define MAXN 100000
10 using namespace std;
11 int n;int sum;int a[MAXN];
12 int biao[MAXN];
13 int read()
14 
15     int x=0;char c=getchar();
16     while(c<0||c>9)c=getchar();
17     while(c>=0&&c<=9)
18     
19           x=(x<<1)+(x<<3)+(c^48);
20           c=getchar();
21     
22     return x;
23 
24 int maxn;
25 int main()
26 
27    n=read();
28    for(int i=1;i<=n;++i)
29    
30        a[i]=read();
31        if(a[i]==i)
32        
33             sum++;
34             biao[i]=1;
35        
36    
37    maxn=sum;
38    for(int i=1;i<=n;++i)
39    
40        int point_l=i-1;int point_r=i+1;int sum_me=sum;
41        while(a[point_l]!=0&&a[point_r]!=0)
42        
43             if(biao[point_l])sum_me--;
44             if(biao[point_r])sum_me--;
45             swap(a[point_l],a[point_r]);
46             if(a[point_l]==point_l)sum_me++;
47             if(a[point_r]==point_r)sum_me++;
48             maxn=max(sum_me,maxn);
49             swap(a[point_l],a[point_r]);
50             //printf("point_l=%d point_r=%d sum_me=%d\n",point_l,point_r,sum_me);
51             point_l--;point_r++;
52        
53        point_l=i;point_r=i+1;sum_me=sum;
54        while(a[point_l]!=0&&a[point_r]!=0)
55        
56             if(biao[point_l])sum_me--;
57             if(biao[point_r])sum_me--;
58             swap(a[point_l],a[point_r]);
59             if(a[point_l]==point_l)sum_me++;
60             if(a[point_r]==point_r)sum_me++;
61             maxn=max(sum_me,maxn);
62             swap(a[point_l],a[point_r]);
63             //printf("---point_l=%d point_r=%d sum_me=%d\n",point_l,point_r,sum_me);
64             point_l--;point_r++;
65        
66    
67    printf("%d\n",maxn);
68 
View Code

100分n*log(n)

假设有个点位置为i权值为a[i]

那么显然它想要作出贡献只能是以(i+a[i])/2为旋转点

那么我们发现,假设我们排序一边(以固定点为关键字),

然后就我们发现(对于同一旋转点)假设从一个区间较小->区间较大,

贡献值的变化只有旋转后,变回相应位置的点,贡献++

同时会有一部分点原来是i==a[i],这些点的贡献减去,前缀和处理

技术图片
  1 //性质::区间的外围一定是可作出贡献点
  2 //排序后每次可贡献点++,固定点--
  3 #include<cstdio>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<cstring>
  8 #include<string>
  9 #include<map>
 10 #include<vector>
 11 #define MAXN 500000
 12 #define ps push_back
 13 #define int long long
 14 using namespace std;
 15 struct nodeint l,r,dian,len;e1[MAXN],e2[MAXN];
 16 int a[MAXN];
 17 int sum[MAXN],biao[MAXN];
 18 int n,maxn;
 19 bool cmp(const node &a,const node &b)
 20 
 21      return (a.dian==b.dian)?(a.len<b.len):(a.dian<b.dian);
 22 
 23 signed main()
 24 
 25     scanf("%lld",&n);
 26     for(int i=1;i<=n;++i)
 27      
 28         scanf("%lld",&a[i]);
 29         sum[i]=sum[i-1];
 30         if(a[i]==i)
 31         
 32            biao[i]++;
 33            sum[i]++;
 34            
 35     
 36     int tot1=0,tot2=0;
 37     for(int i=1;i<=n;++i)
 38     
 39         if((i+a[i])%2==0)
 40         
 41            int zh=(i+a[i])/2;
 42            e1[++tot1].l=min(i,a[i]);
 43            e1[tot1].r=max(i,a[i]);
 44            e1[tot1].dian=zh;
 45            e1[tot1].len=abs(a[i]-i)+1;
 46           //printf("e[%lld].dian=%lld %lld %lld\n",tot1,e1[tot1].dian,e1[tot1].l,e1[tot1].r);   
 47         
 48         else 
 49         
 50            int zh=(i+a[i])/2;
 51            e2[++tot2].l=min(i,a[i]);
 52            e2[tot2].r=max(i,a[i]);
 53            e2[tot2].dian=zh;
 54            e2[tot2].len=abs(a[i]-i)+1;
 55         
 56     
 57     sort(e1+1,e1+tot1+1,cmp);
 58     sort(e2+1,e2+tot2+1,cmp);
 59    /* for(int i=1;i<=tot1;i++)
 60     
 61         
 62     */
 63     int sum1=0;
 64     for(int i=1;i<=tot1;++i)
 65     
 66         //printf("i===%lld\n",i);    
 67         //printf("e[%lld].dian=%lld %lld %lld %lld\n",i,e1[i].dian,e1[i].l,e1[i].r,e1[i].len);
 68         int l,r;
 69         if(e1[i].dian==e1[i-1].dian)
 70         
 71             //printf("case 1:\n");
 72             if(e1[i].len==e1[i-1].len)continue;
 73             l=e1[i].l;r=e1[i].r;
 74             int last_l=e1[i-1].l;int last_r=e1[i-1].r;
 75             if(a[l]==r)sum1++;if(a[r]==l)sum1++;
 76             sum1-=sum[last_l-1]-sum[l];
 77             sum1-=sum[r-1]-sum[last_r];
 78             maxn=max(maxn,sum1);
 79             //printf("sum1=%lld \n",sum1);
 80         
 81         else
 82         
 83              l=e1[i].l;r=e1[i].r;     
 84              sum1=0;
 85              sum1+=sum[e1[i].l-1];
 86              sum1+=sum[n]-sum[e1[i].r];
 87              if(biao[e1[i].dian]==1)sum1++; 
 88              maxn=max(maxn,sum1);
 89              if(l==r)continue;
 90              if(a[l]==r)sum1++;
 91              if(a[r]==l)sum1++;
 92              //printf("l=%lld r=%lld sum1=%lld\n",l,r,sum1);
 93              maxn=max(maxn,sum1);
 94         
 95 
 96     
 97     for(int i=1;i<=tot2;++i)
 98     
 99         int l=0,r=0;
100         //printf("i=%lld\n",i);
101        // //printf("e[%lld].dian=%lld %lld %lld %lld\n",i,e2[i].dian,e2[i].l,e2[i].r,e2[i].len);
102         if(e2[i].dian==e2[i-1].dian)
103         
104             if(e2[i].len==e2[i-1].len)continue;
105             l=e2[i].l;r=e2[i].r;
106             int last_l=e2[i-1].l,last_r=e2[i-1].r;
107             if(a[l]==r)sum1++;if(a[r]==l)sum1++;
108            // printf("sum1=%lld\n",sum,a[l],r);
109             sum1-=sum[last_l-1]-sum[l];
110             sum1-=sum[r-1]-sum[last_r];
111             maxn=max(maxn,sum1);
112             //printf("case 1sum=%lld \n",sum1);
113         
114         else 
115         
116             l=e2[i].l;r=e2[i].r;sum1=0;
117             if(a[l]==r)sum1++;
118             if(a[r]==l)sum1++;
119             sum1+=sum[l-1];
120             sum1+=sum[n]-sum[r];
121             maxn=max(maxn,sum1);
122            // printf("l=%lld r=%lld sum1=%lld\n",l,r,sum1);
123         
124     
125     printf("%lld\n",maxn);
126 
127 /*
128 8
129 2 3 4 1 5 7 8 6 
130 */
View Code

 

以上是关于旋转子段(性质分析)的主要内容,如果未能解决你的问题,请参考以下文章

Hihocoder1673

Codeforces 1175F 尺取法 性质分析

最大子段和——动态规划是如何运作的

linux内核中socket的创建过程源码分析(总结性质)

5.3 数值分析: 差商的定义及性质

LOJ3176「IOI2019」景点划分分析性质,构造