2017.8.13 改题
考完今天的试,充分说明了 对于简单题对拍的重要性 另外对于树的数据生成器,用并查集,但是我想也可以用一遍dfs
T1
给一个n长度的序列,只能修改其中一个数到任意整数(也可以不修改),求最长严格上升子串
solution
先O(n)求出原序列中所有上升子串,枚举每一个点作为要修改的点
分修改后 能把几个序列合并 还是 在原来长度上+1
(挂的原因:少写了一个-1,这个错误对拍一定能拍出来)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define ll long long 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const int INF=(1<<31)-1; 8 const int N=300006; 9 int read() 10 { 11 int ans=0,flag=1;char q=getchar(); 12 while(q<'0'||q>'9'){if(q=='-')flag=-1;q=getchar();} 13 while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();} 14 return ans; 15 } 16 17 int n,ans; 18 int a[N]; 19 int L[N],R[N],cnt,len[N]; 20 21 void hh() 22 { 23 int temp; 24 for(int i=1;i<=cnt;++i) 25 if(ans<len[i]) 26 ans=len[i]; 27 28 if(cnt==1)return ; 29 30 if(len[1]==1) 31 { 32 temp=len[2]+1; 33 if(ans<temp) 34 ans=temp; 35 } 36 else 37 { 38 if(a[R[1]-1]+1<a[R[1]+1]) 39 { 40 temp=len[1]+len[2]; 41 if(ans<temp) 42 ans=temp; 43 } 44 else 45 { 46 temp=len[2]+1; 47 if(ans<temp) 48 ans=temp; 49 } 50 } 51 52 for(int i=2;i<cnt;++i) 53 { 54 if(len[i]==1) 55 { 56 if(a[L[i]-1]+1<a[L[i]+1]) 57 { 58 temp=len[i-1]+len[i]+len[i+1]; 59 if(ans<temp) 60 ans=temp; 61 } 62 else 63 { 64 temp=len[i-1]+1; 65 if(ans<temp) 66 ans=temp; 67 temp=len[i+1]+1; 68 if(ans<temp) 69 ans=temp; 70 } 71 } 72 else 73 { 74 if(a[L[i]-1]+1<a[L[i]+1]) 75 { 76 temp=len[i-1]+len[i]; 77 if(ans<temp) 78 ans=temp; 79 } 80 else 81 { 82 temp=len[i-1]+1; 83 if(ans<temp) 84 ans=temp; 85 } 86 87 if(a[R[i]-1]+1<a[R[i]+1])//a[R[i]-1]+1<a[R[i]+1] 写成了 a[R[i]]+1<a[R[i]+1] 88 { 89 temp=len[i]+len[i+1]; 90 if(ans<temp) 91 ans=temp; 92 } 93 else 94 { 95 temp=len[i+1]+1; 96 if(ans<temp) 97 ans=temp; 98 } 99 } 100 } 101 102 if(len[cnt]==1) 103 { 104 temp=len[cnt-1]+1; 105 if(ans<temp) 106 ans=temp; 107 } 108 else 109 { 110 if(a[L[cnt]-1]+1<a[L[cnt]+1]) 111 { 112 temp=len[cnt-1]+len[cnt]; 113 if(ans<temp) 114 ans=temp; 115 } 116 else 117 { 118 temp=len[cnt-1]+1; 119 if(ans<temp) 120 ans=temp; 121 } 122 } 123 } 124 125 int main(){ 126 127 //freopen("lis8.in","r",stdin); 128 129 n=read(); 130 for(int i=1;i<=n;++i) 131 a[i]=read(); 132 133 for(int i=1;i<=n;++i) 134 { 135 int now=i; 136 while(now<n&&a[now+1]>a[now]) 137 ++now; 138 L[++cnt]=i; 139 R[cnt]=now; 140 len[cnt]=R[cnt]-L[cnt]+1; 141 i=now; 142 } 143 144 /*printf("\n"); 145 for(int i=1;i<=cnt;++i) 146 printf("%d %d\n",L[i],R[i]); 147 printf("\n");*/ 148 149 hh(); 150 cout<<ans; 151 //while(1); 152 return 0; 153 }
T2 中值滤波
给一个长为n的01序列,每次进行一次操作使 a[] → b[]
规则: b[1]=a[1] b[n]=a[1] b[i]={a[i-1],a[i],a[i+1]}中位数
输出 最少几步之后"稳定",无解输出 -1
solution
首先不可能无解,因为两端已经确定
之(da)后(biao)发现连续两个以上的0/1不会在变,并且0 1交替的串从两边向中间趋于稳定,然后找规律就行了
(这个是因为 打表打错了......这个也可以拍出来嘛 )
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define ll long long 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const int INF=(1<<31)-1; 8 const int N=500006; 9 int read() 10 { 11 int ans=0,flag=1;char q=getchar(); 12 while(q<'0'||q>'9'){if(q=='-')flag=-1;q=getchar();} 13 while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();} 14 return ans; 15 } 16 17 int n,a[N],f[N],num,ans; 18 int L[N],R[N],cnt,co[N]; 19 20 int main(){ 21 22 /// freopen("median4.in","r",stdin); 23 24 n=read(); 25 for(int i=1;i<=n;++i) 26 a[i]=read(); 27 a[0]=a[1];a[n+1]=a[n]; 28 29 for(int i=0;i<=n+1;++i) 30 { 31 int now=i; 32 while(now<n+1&&a[now+1]==a[now]) 33 ++now; 34 if(now==i) 35 continue; 36 L[++cnt]=i; 37 R[cnt]=now; 38 co[cnt]=a[i]; 39 i=now; 40 } 41 42 int temp; 43 for(int i=1;i<cnt;++i) 44 { 45 if(co[i]==co[i+1]) 46 { 47 for(int j=R[i]+1;j<L[i+1];++j) 48 a[j]=co[i]; 49 temp=(L[i+1]-R[i]-1-1)/2; 50 if(temp==0) 51 { 52 if(ans<1) 53 ans=1; 54 } 55 else 56 if(temp&1) 57 { 58 if(ans<temp+1) 59 ans=temp+1; 60 } 61 else 62 { 63 if(ans<temp+1) 64 ans=temp+1; 65 } 66 } 67 else 68 { 69 temp=(L[i+1]-R[i]-1)/2; 70 for(int j=R[i]+1;j<=R[i]+temp;++j) 71 a[j]=co[i]; 72 for(int j=L[i+1]-temp;j<L[i+1];++j) 73 a[j]=co[i+1]; 74 if(ans<temp) 75 ans=temp; 76 } 77 } 78 79 printf("%d\n",ans); 80 for(int i=1;i<=n;++i) 81 printf("%d ",a[i]); 82 83 // while(1); 84 return 0; 85 }
T3 约会
给一个n个点 n-1条边的树,m次询问 到x和y距离相等的点有几个
solution
先求出x→y路径长度len,如果len&1,那就无解
在求出路径上的中点,如果是LCA,那 ans=(n-size[LCA])+size[son[LCA]](son!=x/y到LCA路径上的点)
如果不是LCA ans=size[son[LCA']] (son!=fa[LCA']/x/y到LCA'路径上的点)
(忠告:不要用树链剖分,树上倍增大法好!!!)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 const int N=100006; 7 struct son 8 { 9 int v,next; 10 }; 11 son a1[N*5]; 12 int first[N*5],e; 13 void addbian(int u,int v) 14 { 15 a1[e].v=v; 16 a1[e].next=first[u]; 17 first[u]=e++; 18 } 19 20 int n,u,o,m; 21 int fa[N],dep[N],q[N][33],size[N]; 22 23 void dfs1(int x) 24 { 25 size[x]=1; 26 for(int i=first[x];i!=-1;i=a1[i].next) 27 { 28 int temp=a1[i].v; 29 if(temp==fa[x])continue; 30 dep[temp]=dep[x]+1; 31 fa[temp]=x; 32 dfs1(temp); 33 size[x]+=size[temp]; 34 } 35 } 36 37 void chu() 38 { 39 mem(q,-1); 40 for(int i=0;i<=n;++i)//点的编号有0 41 q[i][0]=fa[i]; 42 for(int j=1;(1<<j)<=n;++j) 43 for(int i=0;i<=n;++i) 44 if(q[i][j-1]!=-1) 45 q[i][j]=q[q[i][j-1]][j-1]; 46 } 47 48 int LCA(int x,int y) 49 { 50 if(dep[x]<dep[y]) 51 swap(x,y); 52 int tx=x,ty=y,lca,dx=0,dy=0,ans=0;//lca是假的lca,其实是中点 53 int num=0; 54 while((1<<num)<=dep[x])++num; 55 for(int j=num;j>=0;--j) 56 if(dep[x]-(1<<j)>=dep[y]) 57 { 58 x=q[x][j]; 59 dx+=(1<<j); 60 } 61 62 //printf("1\n"); 63 64 if(x==y) 65 { 66 if(dx&1) 67 return 0; 68 dx>>=1; 69 --dx;//*** 70 x=tx; 71 for(int j=num;j>=0;--j) 72 if((1<<j)<=dx) 73 { 74 x=q[x][j]; 75 dx-=(1<<j); 76 } 77 lca=fa[x]; 78 for(int i=first[lca];i!=-1;i=a1[i].next) 79 { 80 int temp=a1[i].v; 81 if(temp==fa[lca]||temp==x)continue; 82 ans+=size[temp]; 83 } 84 return ans+1; 85 } 86 87 //printf("2\n"); 88 89 for(int j=num;j>=0;--j) 90 if(q[x][j]!=-1&&q[x][j]!=q[y][j]) 91 { 92 x=q[x][j];dx+=(1<<j); 93 y=q[y][j];dy+=(1<<j); 94 } 95 ++dx;++dy; 96 if((dx+dy)&1) 97 return 0; 98 99 //printf("4\n"); 100 101 if(dx==dy) 102 { 103 lca=fa[x]; 104 //printf("lca=%d x=%d y=%d\n",lca,x,y); 105 for(int i=first[lca];i!=-1;i=a1[i].next) 106 { 107 int temp=a1[i].v; 108 if(temp==fa[lca]||temp==x||temp==y)continue; 109 ans+=size[temp]; 110 } 111 ++ans; 112 ans+=(n-size[lca]); 113 return ans; 114 } 115 116 //printf("3\n"); 117 118 int val=(dx+dy)>>1; 119 --val;//*** 120 x=tx; 121 for(int j=num;j>=0;--j) 122 if((1<<j)<=val) 123 { 124 x=q[x][j]; 125 val-=(1<<j); 126 } 127 lca=fa[x]; 128 for(int i=first[lca];i!=-1;i=a1[i].next) 129 { 130 int temp=a1[i].v; 131 if(temp==fa[lca]||temp==x)continue; 132 ans+=size[temp]; 133 } 134 return ans+1; 135 } 136 137 138 int main(){ 139 140 //freopen("1.txt","r",stdin); 141 142 //freopen("date.in","r",stdin); 143 //freopen("date.out","w",stdout); 144 //freopen("2.txt","w",stdout); 145 146 mem(first,-1); 147 mem(fa,-1); 148 149 scanf("%d",&n); 150 for(int i=1;i<n;++i) 151 { 152 scanf("%d%d",&u,&o); 153 addbian(u,o); 154 addbian(o,u); 155 } 156 157 dfs1(2);//我用1不行..... 158 chu(); 159 160 scanf("%d",&m); 161 for(int i=1;i<=m;++i) 162 { 163 //printf("i=%d\n",i); 164 scanf("%d%d",&u,&o); 165 if(u==o) 166 printf("%d\n",n);//竟然有重的 167 else 168 printf("%d\n",LCA(u,o)); 169 } 170 171 //while(1); 172 return 0; 173 }
总结
1.对于简单题,一定要打对拍,不然会死的很惨
2.还有就是不要太关注平时考试成绩,要注重于学习时的专注、思考与坚持
3.如果你看到一个题数据范围不正常的小,肯定跟正解有关系