描述
你正在协助某人开发某种新的 Linux 下的中文字体。
现在需要给上图里的黄点做「位置锚固」,然而有些黄点的位置可以由「插值(IUP)」确定,这样就可以减少锚固的数量。
例如,在上图中,#46 #49 #52 #53 的位置可以由 #42 和 #57 插值得到, 我就不需要去锚固它们,只需要固定 #42 和 #57 就可以了。 可以给这个字减少至少 12 字节 ……
抽象一下问题,现在给出输入数组 a,
定义 ax 可以被 al 和 ar 插值得到为:
存在 l < x < r
使得 al ≤ ax ≤ ar 或者 al ≥ ax ≥ ar。
求最少的「锚固」元素的数目,使得非锚固元素都可以由其左右最靠近它的锚固元素插值得到。并输出锚固元素的下标。
输入
第一行输入一个数 n,表示数组的大小(1 ≤ n ≤ 105)。 接下来的一行,输入一行 n 个整数 a1, a2, ..., an,表示数组中的元素(1 ≤ ai ≤ 109)。所有 ai 互不相同。
输出
输出的第一行包含一个整数 ans,表示锚固元素的数目。 接下来一行包含 ans 个递增的整数,表示锚固元素的下标。
提示
额外的样例数据:
样例输入 | 样例输出 |
7 1 2 3 10 5 6 4 |
3 1 4 7 |
样例输入
8 3 4 2 1 8 5 7 6
样例输出
7 1 2 4 5 6 7 8 首先左右端点是一定要选的,根据这个性质。所以我们可以用solve(l,r)表示处理[l,r]区间,且已经选了l和r。那么我们求出[l,r]的最小值和最大值的位置,如果其中一个位置不符合要求,肯定要选成锚固元素,递归处理即可。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=100010; int A[maxn],cnt,ans[maxn]; int mx[maxn][20],mn[maxn][20],Log[maxn]; void init(int n) { Log[0]=-1; rep(i,1,n) Log[i]=Log[i>>1]+1; rep(i,1,n) mx[i][0]=mn[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) { int v1=mx[i][j-1],v2=mx[i+(1<<j-1)][j-1]; mx[i][j]=A[v1]>A[v2]?v1:v2; v1=mn[i][j-1],v2=mn[i+(1<<j-1)][j-1]; mn[i][j]=A[v1]<A[v2]?v1:v2; } } void query(int l,int r,int& p1,int& p2) { int k=Log[r-l+1]; p1=A[mx[l][k]]>A[mx[r-(1<<k)+1][k]]?mx[l][k]:mx[r-(1<<k)+1][k]; p2=A[mn[l][k]]<A[mn[r-(1<<k)+1][k]]?mn[l][k]:mn[r-(1<<k)+1][k]; } void solve(int l,int r) { if(l+1>=r) return; int p1,p2;query(l+1,r-1,p1,p2); if(A[p2]<min(A[l],A[r])) ans[++cnt]=p2,solve(l,p2),solve(p2,r); else if(A[p1]>max(A[l],A[r])) ans[++cnt]=p1,solve(l,p1),solve(p1,r); } int main() { int n=read(); rep(i,1,n) A[i]=read(); init(n); ans[++cnt]=1;ans[++cnt]=n; solve(1,n); printf("%d\n",cnt); sort(ans+1,ans+cnt+1); printf("%d",ans[1]);rep(i,2,cnt) printf(" %d",ans[i]); return 0; }
时间: 2024-10-10 08:45:35