2017.6.11 NOIP模拟赛
题目链接:
https://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\n"); ok=true;} } if(top>1&&!ok) { for(int i=1;i<top;i++) if(st[i]>st[i+1]) { printf("J\n"); ok=true; break; } } if(!ok) printf("Y\n"); } }
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\n",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\n",i,j,k); } } printf("%d",ans/4); }
考场上打的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); }
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(""); } }
法二:堆