NOIP 2011 题解+代码
来源:互联网 发布:手机景点讲解器软件 编辑:程序博客网 时间:2024/05/19 03:24
这年的题是昨天写完的,但没有发博客。。。
依旧不贴题面了。
铺地毯。
简单模拟。倒着搜就行了,遇到第一个满足的就break掉。
#include<bits/stdc++.h>using namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f;}const int N = 10000 + 10;int n;struct node{ int x1,x2,y1,y2;}a[N];int main(){ n=read(); for(int i=1;i<=n;++i){ int g,k; a[i].x1=read(),a[i].y1=read(),g=read(),k=read(); a[i].x2=a[i].x1+g-1,a[i].y2=a[i].y1+k-1; } int x=read(),y=read(); for(int i=n;i>=1;--i){ if(a[i].x1<=x&&a[i].x2>=x&&a[i].y1<=y&&a[i].y2>=y) { printf("%d\n",i); return 0; } } printf("-1\n"); return 0;}
选择客栈。
正解好像是dp,不过可以用st表来水。。用一个指针记录第一个人选i这个位置,第二个人至少应该选什么位置才会有满足条件的咖啡厅。再在输入的时候记录一个前缀和,表示到i这个位置风格为k的咖啡厅有多少个。每次移动指针,统计答案就行了。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define ll long longusing namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f;}const int N = 200000 + 10;const int P = 20;const int K = 50 + 5;inline int Min(int a,int b) {return a<b?a:b;}inline int Max(int a,int b) {return a>b?a:b;}int n,k,p;int a[N],b[N],sum[N][K];int logn[N],st[N][P];void st_table(){ logn[1]=0; for(int i=2;i<=n;++i) logn[i]=logn[i>>1]+1; for(int i=1;i<=n;++i) st[i][0]=a[i]; for(int j=1;j<P;++j){ for(int i=1;i+(1<<j)-1<=n;++i){ st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); } }}int query(int l,int r){ int len=r-l+1; int k=logn[len]; return min(st[l][k],st[r-(1<<k)+1][k]);}int main(){ n=read(),k=read(),p=read(); for(int i=0;i<k;++i) sum[0][i]=0; for(int i=1;i<=n;++i) { b[i]=read(),a[i]=read(); for(int j=0;j<k;++j) sum[i][j]=sum[i-1][j]+(b[i]==j); } st_table(); int tail=1; while(query(1,tail)>p) ++tail; ll ans=sum[n][b[1]]-sum[Max(tail-1,1)][b[1]]; for(int i=2;i<=n;++i){ tail=max(tail,i); while(query(i,tail)>p&&tail<n) ++tail; if(tail==n&&query(i,tail)>p) break; ans+=sum[n][b[i]]-sum[Max(tail-1,i)][b[i]]; } cout<<ans<<endl; return 0;}
玛雅游戏。
这个有毒!!它不让我过!!!
代码只有90分,但是数据在本机是能过的,以前(今天3月份)有AC的代码,也不想改了。
就是搜索,不剪枝也能过。注意如果有掉落或清除的话,掉落函数和清除函数就要一直调用,因为原来的掉落/清除可能会引发新的。
#include<bits/stdc++.h>using namespace std;const int N = 10;int n;int a[N][N],cnt[N];bool check(){ for(int i=0;i<5;++i) for(int j=0;j<7;++j) if(a[i][j]) return false; return true;}struct node{ int step,x,y;}b[100];bool fallen(int i){ bool flag=false; for(int j=6;j>0;--j){ if(a[i][j]&&(!a[i][j-1])) flag=true,swap(a[i][j],a[i][j-1]); } return flag;}void fallen(){ for(int i=0;i<5;++i){ while(fallen(i)); }}bool c[N][N];bool clear(){ memset(c,0,sizeof(c)); for(int i=0;i<3;++i){ for(int j=0;j<7;++j){ if(a[i][j]!=0&&a[i][j]==a[i+1][j]&&a[i+1][j]==a[i+2][j]){ c[i][j]=c[i+1][j]=c[i+2][j]=true; } } } for(int i=0;i<5;++i){ for(int j=0;j<5;++j){ if(a[i][j]!=0&&a[i][j]==a[i][j+1]&&a[i][j+2]==a[i][j+1]){ c[i][j]=c[i][j+1]=c[i][j+2]=true; } } } bool flag=false; for(int i=0;i<5;++i){ for(int j=0;j<7;++j){ if(c[i][j]) a[i][j]=0,flag=true; } } return flag;}bool dfs(int d){ int c[N][N]; while(1){ fallen(); if(!clear()) break; } if(d>n){ if(check()) return true; return false; } memcpy(c,a,sizeof(c)); for(int i=0;i<5;++i) for(int j=0;j<7;++j){ if(!a[i][j]) continue; int x=i+1,y=j; if(x<5&&a[x][y]!=a[i][j]) { swap(a[x][y],a[i][j]); if(dfs(d+1)) { b[d].step=1,b[d].x=i,b[d].y=j; return true; } memcpy(a,c,sizeof(a)); } x=i-1,y=j; if(x>=0&&a[x][y]==0){ swap(a[x][y],a[i][j]); if(dfs(d+1)) { b[d].step=-1,b[d].x=i,b[d].y=j; return true; } memcpy(a,c,sizeof(a)); } }}int main(){ scanf("%d",&n); for(int i=0;i<5;++i){ int x;scanf("%d",&x); while(x){ a[i][cnt[i]++]=x; scanf("%d",&x); } } if(!dfs(1)) {printf("-1");return 0;} for(int i=1;i<=n;++i) printf("%d %d %d\n",b[i].x,b[i].y,b[i].step); return 0;}
计算系数
杨辉三角和快速幂。。。
#include<bits/stdc++.h>#define ll long longusing namespace std;const int N = 1000 + 10;const int mod = 10007;ll c[N][N];int a,b,k,n,m;ll mpow(ll a,ll b){ ll rt=1; for(rt;b;b>>=1,a=a*a%mod) if(b&1) rt=rt*a%mod; return rt;}int main(){ for(int i=1;i<=1002;++i){ for(int j=1;j<=i;++j){ if(j==1||j==i) c[i][j]=1; else c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } scanf("%d%d%d%d%d",&a,&b,&k,&n,&m); ll ans=mpow(a,n)*mpow(b,m)%mod*c[k+1][1+k-n]%mod; cout<<ans<<endl; return 0;}
聪明的质检员
二分答案,每次check的时候先更新一下前缀和。注意要记录s的前驱和后驱,然后比较哪个更接近。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define ll long longusing namespace std;inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f;}const int N = 200000 + 10;int n,m;ll s;int l[N],r[N],w[N],v[N];ll c1[N],c2[N];ll getans(ll ww){ ll ans=0; c1[0]=c2[0]=0; for(int i=1;i<=n;++i){ if(w[i]>=ww) c1[i]=c1[i-1]+1,c2[i]=c2[i-1]+v[i]; else c1[i]=c1[i-1],c2[i]=c2[i-1]; } for(int i=1;i<=m;++i){ ll num=c1[r[i]]-c1[l[i]-1],sum=c2[r[i]]-c2[l[i]-1]; ans+=1LL*num*sum; } return ans;}int main(){ n=read(),m=read(),s=read(); ll lf=1,rg=1; for(int i=1;i<=n;++i) w[i]=read(),v[i]=read(),rg=max(rg,1LL*w[i]); for(int i=1;i<=m;++i) l[i]=read(),r[i]=read(); ll ans1=0,ans2=0;rg+=1; while(lf<=rg){ ll mid=(lf+rg)/2; ll x=getans(mid); if(x<=s) ans2=x,rg=mid-1; else lf=mid+1,ans1=x; } printf("%lld\n",min(s-ans2,ans1-s)); return 0;}
观光公交。
这道题调了好久。我可能是废了。
贪心。很容易求出如果一个加速器都不使用花费的总时间。对于加速器,就一个一个地处理。每次找到两个站台之间的距离, 求出如果改变这个速度,会减少多少人的时间,然后求出一个合法的最大值(当速度已经变为0了,即使改变它会使更多人时间减少也不可取了),每次都减去这个最大值就行了。O(nk)居然能过。
之前想的各种复杂。因为到每一个站台都有一个能减少的最多的时间的限制,如果多余了这个时间其实还不如不使用加速器,然后就求出如果改变这段时间会有多少人受益。按人数来排序。但其实每次改变之后会有后效性,各种麻烦。。不如暴力改。。
#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f;}const int N = 1000 + 10;const int M = 10000 + 10;int n,m,k;int d[N],st[M],a[M],b[M],ed[M],com[N],mx[N];int far[N],sum[N];ll ans=0,ans1=0;void zero(){ com[1]=0; for(int i=2;i<=n;++i) com[i]=max(com[i-1],mx[i-1])+d[i-1]; for(int i=1;i<=m;++i) ans+=com[b[i]]-st[i];}int main(){ n=read(),m=read(),k=read(); for(int i=1;i<n;++i) d[i]=read(); for(int i=1;i<=m;++i) st[i]=read(),a[i]=read(),b[i]=read(),mx[a[i]]=max(mx[a[i]],st[i]),++sum[b[i]]; zero(); for(int i=2;i<=n;++i) sum[i]+=sum[i-1]; while(k--){ far[n]=n; for(int i=n-1;i>=2;--i){ if(mx[i]<com[i]) far[i]=far[i+1]; else far[i]=i; } int mmax=0,pos; for(int i=2;i<=n;++i) if(sum[far[i]]-sum[i-1]>mmax&&d[i-1]) mmax=sum[far[i]]-sum[i-1],pos=i; if(mmax==0) break; ans1+=mmax;--d[pos-1]; for(int i=2;i<=n;++i) com[i]=max(com[i-1],mx[i-1])+d[i-1]; } printf("%lld\n",ans-ans1); return 0;}
阅读全文
0 0
- NOIP 2011 题解+代码
- NOIP 2009 题解+代码
- NOIP 2010 题解+代码
- NOIP 2016 题解+代码
- NOIP难度 零件分组 stick 题解&代码
- NOIP 2013 提高组题解 【附AC代码】
- NOIP 2010 题解
- NOIP 2012 题解
- NOIP模拟21题解
- NOIP模拟题题解
- NOIP 2015 简要题解
- NOIP-2016-普及-题解
- NOIP-2009-提高-题解
- Noip 2013 day1 题解
- NOIP 2004 题解
- NOIP 2010 题解
- NOIP 2015 题解
- NOIP普及组题解
- [Kubernetes] CentOS 7 Etcd 集群部署教程
- ngx.req和get/post参数获取
- 读取ini配置文件
- bootstrap 自适应全屏轮播可支持左右滑动
- spring Ioc底层原理
- NOIP 2011 题解+代码
- Qt的信号与槽机制理解
- JDBC连接数据库(statement)
- 入it行感悟
- ZOJ 3988 && 2017CCPC秦皇岛 H:Prime Set(二分匹配)
- Spring + Activiti + Drools整合的请假例子
- 配置caffe-SSD
- C#基础知识复习
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(十)SVN搭建