#1074 : 字体设计

描述

你正在协助某人开发某种新的 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)。所有 a互不相同。

输出

输出的第一行包含一个整数 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;
}
View Code

 

posted @ 2015-09-12 11:09  wzj_is_a_juruo  阅读(334)  评论(0编辑  收藏  举报