2017.6.11 NOIP模拟赛

题目链接:

http://files.cnblogs.com/files/TheRoadToTheGold/2017-6.11NOIP%E6%A8%A1%E6%8B%9F%E8%B5%9B.zip

期望得分:100+30+100=230

实际得分:0+30+100=130

T1 盘子序列

数据离散化,模拟栈

将盘子大小离散化 1——n

指针now开始指向1,依次递增,模拟初始盘堆A最上面的盘子

用a[i]存储收到的离散化之后的第i个盘子的大小,收到盘子的顺序也看做一个栈,记为栈C

st[]模拟盘堆B, top指针指向栈顶

 

然后分4种情况讨论

1、a[i]=now 初始盘堆A的最上面的盘子直接放到了栈C  now++

2、st[i]=now 盘堆B最上面的盘子放到栈C ,top--

3、盘堆A还有盘子,盘堆AB的顶端都不等于now,一直把A的盘子往B上放,直到等于now 或A没有盘子了

4、都不符合上面3种,有危险

最后判断st即B是否是升序排列,是则没有危险,否则有危险

#include<cstdio>
#include<algorithm>
#define N 100001
using namespace std;
int n,now,x;
int st[N],top,a[N];
bool ok;
struct node
{
    int num,id;
}e[N];
bool cmp(node p,node q)
{
    return p.num<q.num;
}
int main()
{
    freopen("disk.in","r",stdin);
    freopen("disk.out","w",stdout);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++) scanf("%d",&e[i].num),e[i].id=i;
        sort(e+1,e+n+1,cmp);
        for(int i=1;i<=n;i++) a[e[i].id]=i;
        ok=0; top=0; now=1;
        for(int i=1;i<=n;i++)
        {
            if(ok) continue;
            if(a[i]==now) now++;
            else if(top&&a[i]==st[top]) top--;
            else if(now<n&&a[i]!=now) 
            {
                while(a[i]!=now && now<n) st[++top]=now++;
                now++;
            }
            else  { printf("J
"); ok=true;}
        }
        if(top>1&&!ok)
        {
            for(int i=1;i<top;i++) 
             if(st[i]>st[i+1])
             {
                  printf("J
");
                 ok=true; break;
             }
        }
        if(!ok) printf("Y
");
    }
}
View Code

 0分原因:

第三种情况:

else if(now<n&&a[i]!=now)
{
  while(a[i]!=now && now<n) st[++top]=now++;
  now++;
}

while里漏了now<n,无限循环RE

T2 四轮车

离散化坐标

枚举两个点1、2固定一条边,根据正方形四边相等

那么

x3=x2+y2-y1; y3=y2+x1-x2;
x4=x1+y2-y1; y4=y1+x1-x2;

判断这两个点是否出现过

因为可能有重复点,所以去重后,设点出现了k次

没找到一个满足条件的,ans+=k1*k2*k3*k4

正方形的4条边都有可能是枚举的那条边,所以最后ans/4

代码中判断3、4是否存在的方法:

设离散化后的横坐标为nx,纵坐标为ny

[nx][ny] 出现过 (有序数对(nx,ny))

同时,hash_x[nx]=x,hash_y[ny]=y

hash[]:排序后的原数据

#include<cstdio>
#include<algorithm>
#define N 1001

using namespace std;

int n,x[N],y[N],ans;
int sum[N][N];
bool v[N];
int eg[N][N];
int hashx[N+1],hashy[N+1],totx,toty,nx,ny;
int newx[N],newy[N];

int x1,x2,y1,y2,x3,x4,y3,y4,k1,k2,k3,k4;
void solve(int a,int b)
{
    x1=x[a]; x2=x[b]; y1=y[a]; y2=y[b];
    x3=x2+y2-y1; y3=y2+x1-x2;
    x4=x1+y2-y1; y4=y1+x1-x2;
    nx=lower_bound(hashx+1,hashx+totx+1,x3)-hashx;
    ny=lower_bound(hashy+1,hashy+toty+1,y3)-hashy;
    if(!(eg[nx][ny] && hashx[nx]==x3 && hashy[ny]==y3)) return ;
    k3=sum[nx][ny];
    nx=lower_bound(hashx+1,hashx+totx+1,x4)-hashx;
    ny=lower_bound(hashy+1,hashy+toty+1,y4)-hashy;
    if(!(eg[nx][ny] && hashx[nx]==x4 && hashy[ny]==y4)) return ;
    k4=sum[nx][ny];
    k1=sum[newx[a]][newy[a]]; k2=sum[newx[b]][newy[b]];
    ans+=k1*k2*k3*k4;
    //if(k1*k2*k3*k4) printf("%d,%d %d,%d %d,%d %d,%d
",x1,y1,x2,y2,x3,y3,x4,y4);
//    return k1*k2*k3*k4;
}

int main()
{
    /*freopen("car.in","r",stdin);
    freopen("car.out","w",stdout);*/
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d%d",&x[i],&y[i]);
        hashx[i]=x[i]; hashy[i]=y[i];
    }
    sort(hashx+1,hashx+n+1);
    sort(hashy+1,hashy+n+1);
    totx=unique(hashx+1,hashx+n+1)-(hashx+1);
    toty=unique(hashy+1,hashy+n+1)-(hashy+1);
    for(int i=1;i<=n;i++)
    {
        nx=lower_bound(hashx+1,hashx+totx+1,x[i])-hashx;
        ny=lower_bound(hashy+1,hashy+toty+1,y[i])-hashy;
        newx[i]=nx; newy[i]=ny;
        sum[nx][ny]++;
        if(!eg[nx][ny]) eg[nx][ny]=i;
        else  v[i]=true;
    }
    for(int i=1;i<=n;i++)
    {
        if(v[i]) continue;
        for(int j=1;j<=n;j++)
        {
            if(v[j] || i==j) continue;
            solve(i,j);
            //if(k) printf("%d %d %d
",i,j,k);
        }
    }
    printf("%d",ans/4);
}
View Code

考场上打的30分暴力:

n^4枚举4个点,如果能构成正方形,ans++

构成正方形的4个点,固定住1个,剩余3个有3!种排法

所以同一个正方形会被重复计算4*3!=24次

最后ans/24

#include<cstdio>
#include<queue>
#define ref(x) for(x=1;x<=n;x++)
#define N 1001

using namespace std;

int n,x[N],y[N],ans;

inline int Length(int i,int j)
{
    return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]) ;
} 

int main()
{
    freopen("car.in","r",stdin);
    freopen("car.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
    int a,b,c,d;
    bool ok;
    ref(a)
     ref(b)
     {
         if(a==b) continue;
         ref(c)
         {
             if(c==a||c==b) continue;
             ref(d)
             {
                 if(d==a||d==b||d==c) continue;
                 ok=false;
                if((Length(a,b)==Length(b,c)) && (Length(b,c)==Length(c,d)) && (Length(c,d)==Length(d,a))) ok=true;
                else if((Length(a,b)==Length(b,d)) && (Length(b,d)==Length(d,c)) && (Length(d,c)==Length(c,a))) ok=true;
                else if((Length(a,c)==Length(c,b)) && (Length(c,b)==Length(b,d)) && (Length(b,d)==Length(d,a))) ok=true;
                else if((Length(a,c)==Length(c,d)) && (Length(c,d)==Length(d,b)) && (Length(d,b)==Length(b,a))) ok=true;
                else if((Length(a,d)==Length(d,b)) && (Length(d,b)==Length(b,c)) && (Length(b,c)==Length(c,a))) ok=true;
                else if((Length(a,d)==Length(d,c)) && (Length(d,c)==Length(c,b)) && (Length(c,b)==Length(b,a))) ok=true;
                if(ok) ans++;
            }
        }
     }
     printf("%d",ans/24);
}
View Code

T3 点名

注:本题题目有误,应该是询问身高第k矮

法一:主席树查询区间k值

#include<cstdio>
#include<algorithm>
#define N 30001

using namespace std;

int n,m,now,x,tot,ans;
long long high[N],tmp[N];
int hash[N];
int sum[N*4];

int read1(int &x)
{
    x=0; char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); }
}
long long read2(long long &x)
{
    x=0; char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } 
}
void output(long long x)
{
    if(x/10) output(x/10);
    putchar(x%10+'0');
}

struct President
{
    void insert(int k,int l,int r,int pos)
    {
        sum[k]++;
        if(l==r) return;
        int mid=l+r>>1;
        if(pos<=mid) insert(k<<1,l,mid,pos);
        else insert(k<<1|1,mid+1,r,pos);
    }
    int query(int k,int l,int r,int w)
    {
        if(l==r) return l;
        int mid=l+r>>1;
        if(w<=sum[k<<1]) return query(k<<1,l,mid,w);
        return query(k<<1|1,mid+1,r,w-sum[k<<1]);
    }
};

President Tree;

int main()
{
    freopen("rollcall.in","r",stdin);
    freopen("rollcall.out","w",stdout);
    read1(n); read1(m);
    int tot=n;
    for(int i=1;i<=n;i++) read2(high[i]),tmp[i]=high[i];
    sort(high+1,high+n+1);
    tot=unique(high+1,high+n+1)-(high+1);
    for(int i=1;i<=n;i++) hash[i]=lower_bound(high+1,high+tot+1,tmp[i])-high;
    
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        while(now!=x)
        {
            Tree.insert(1,1,tot,hash[now+1]);
            now++;
        }
        ans=Tree.query(1,1,tot,i);
        output(high[ans]);
        puts("");
    }
}
View Code

 法二:堆

http://www.cnblogs.com/TheRoadToTheGold/p/6995106.html

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6985388.html