大连网络赛。当时挺混乱的,其实根本都没看这道题。后来看了题解觉得用的方法很巧妙。
值得学习。
同时回忆起一道以前的题目。
用的都是类似的思想。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int t,n,q,l,r,ans,modpos;
int a[100005];
int rightpos[100005];
int main()
{
scanf("%d",&t);
while(t--)
{
cin>>n;
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(rightpos,inf,sizeof(rightpos));
for(int i=n-1; i>=1; i--)
{
int k=i+1;
while(1)
{
if(a[i]>a[k]) //找到右边的数比自己小,对答案有影响,存下这个位置
{
rightpos[i]=k;
break;
}
if(rightpos[k]==inf)//找到最后
break;
k=rightpos[k];
}
}
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&l,&r);
ans=a[l];
modpos=rightpos[l];
while(modpos<=r)
{
ans%=a[modpos];
if(ans==0)
break;
modpos=rightpos[modpos];
}
printf("%d\n",ans);
}
}
return 0;
}
思路很简单,就是一直找右边的第一个比这个数小的数。然后不断的存起来,从左往右更新是n^2,从右往左更新最差是n。思路很巧妙,不断的递归往右侧找第一个出现的,小于当前位置的这个数的位置。
当时第一次启蒙我的题目是
the nearest taller cow
题目是在牛的左侧或者右侧找到最近的一个比自己高的牛的位置。然后求平均值。
也是用的类似的方法,从前往后更新出每个点往左边的第一个比他大的值。
在从右往左更新出在右边的第一个比这个数大的值。
最后求和求平均值
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define eps 1e-7
int n,pos;
int a[1000005];
int rightpos[1000005],leftpos[1000005];
double ans;
int main()
{
while(~scanf("%d",&n))
{
ans=0;
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
a[0]=inf;
a[n+1]=inf;
memset(rightpos,inf,sizeof(rightpos));
memset(leftpos,inf,sizeof(leftpos));
for(int i=1; i<=n; i++)
{
pos=i-1;
while(a[pos]<=a[i])
pos=leftpos[pos];
leftpos[i]=pos;
}
for(int i=n; i>=1; i--)
{
pos=i+1;
while(a[pos]<=a[i])
pos=rightpos[pos];
rightpos[i]=pos;
}
for(int i=1; i<=n; i++)
{
//cout<<leftpos[i]<<" "<<rightpos[i]<<endl;
if(leftpos[i]==0)
leftpos[i]=-inf;
if(rightpos[i]==n+1)
rightpos[i]=inf;
ans+=min(min(i-leftpos[i],rightpos[i]-i),n);
}
//cout<<ans<<endl;
printf("%.2f\n",ans/n+eps);
}
return 0;
}