1014
Posted 神犇(shenben)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1014相关的知识,希望对你有一定的参考价值。
评测数据下载:https://yunpan.cn/cvRbFGpVQ6Enj (提取码:838e)
2016.10.14
T1.楼
【问题背景】
zhx 为他的妹子造了一幢摩天楼。
【问题描述】
zhx 有一幢摩天楼。 摩天楼上面有 M 个观光电梯,每个观光电梯被两个整数u " ,d " 描述。每个电梯只有两个按钮, (针对第 i 个电梯)两个按钮分别可以使
电梯向上u" 层向下d" 层。摩天楼的高度是无限的,但是电梯不可以钻入地下,
也就是说是有下限的。每层楼用整数标记,以 0 作为地面这一层的标记。
zhx 去陪他妹子了,留你一个人在摩天楼的 0 层,现在你想知道,仅可以选择 M 个电梯中的一个乘坐(不可以中途换电梯),按电梯中的按钮 N 次后(每次两个按钮选一个按) ,可以到达的最低楼层数。按电梯的过程中请注意,如果当前所在楼层数小于你选择的d" ,你将无法选择电梯向下运行。
【输入格式】
第一行两个数 N 和 M,如题目描述。
接下来 M 行,每行两个整数d " 和u " 。
【输出格式】
仅一行一个整数,包含所求的答案。
【样例输入】
10 3
15 4
15 12
7 12
【样例输出】
13
【数据范围与规定】
对50%的数据,所有1≤N,M≤1000。
对于100%的数据,所有1≤N≤10^7,1≤M≤2000,1≤u, d≤10^5 。
题解:
思路题,想想就想出来了
很容易想到n*m的做法,就是对于每个i枚举一个合适的j,使上升和下降的差值最小,然后我们可以把这个j算出来,省去第二维循环。
100分代码:
#include<cstdio> #include<algorithm> #include<iostream> #define ll long long using namespace std; const int N=1e5+10; inline const ll read(){ register ll x=0; register char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar(); return x; } ll n,m,up[N],dn[N],G[N]; ll ans=0x7fffffff; int main(){ freopen("building.in","r",stdin); freopen("building.out","w",stdout); n=read();m=read(); for(ll i=1;i<=m;i++) up[i]=read(),dn[i]=read(); for(ll i=1;i<=m;i++){ ll uc=(dn[i]*n)/(dn[i]+up[i]); ll dc=n-uc; for(ll j=-10;j<=10;j++) if(uc+j>=0&&dc-j>=0&&(uc+j)*up[i]-(dc-j)*dn[i]>=0) ans=min(ans,(uc+j)*up[i]-(dc-j)*dn[i]); } cout<<ans; return 0; }
std神奇&简介版代码:
#include<iostream> #include<cstdio> #define ll long long using namespace std; int n, m, u, d; ll ans=1LL<<60; int main(){ freopen("building.in","r",stdin); freopen("building.out","w",stdout); ios::sync_with_stdio(false); cin>>n>>m; while(m--){ cin>>u>>d; ll a=(ll)u*n; ll b=u+d; ll c=a%b; if(c<ans) ans=c; } cout<<ans; return 0; }
T2.读
【问题背景】
zhx 为他的妹子制造了一个特别的图灵机(的磁带) 。
【问题描述】
有一个两端无限长的磁带,有N 个读取指针在某些位置,需要读取 M 个位置上的数据。每一个单位时间每个读取指针都可以向左或向右移动一格。如果存在某个时刻某个读取指针在某一个位置上(包括0时刻),那么这个位置上
的数据就会被读取。(注意,不需要读取的位置也能被指针经过)
zhx 去陪妹子了,现在你需要帮他解决一个问题,最少经过多少时间,M个需要读取的位置都能被读取?
【输入格式】
第一行两个整数N,M,表示指针数和需要读取的位置数。
接下来一行N 个整数,a " 表示第 i 个指针初始位置。
接下来一行 M 个整数,b " 表示第 i 个需要读取的位置。
【输出格式】
一行一个整数,代表需要的最小时间。
【样例输入】
3 4
2 5 6
1 3 6 8
【样例输出】
2
【样例输入】
3 3
1 2 3
1 2 3
【样例输出】
0
P69 读
第 4 页 共 6 页
【数据规模与约定】
对于10%的数据,满足N = 1。
对于另外30%的数据,满足N,M≤ 4 , a " ,b " ≤ 15。
对于100%的数据, 满足1≤N,M≤10 ^5, 0 ≤ a , b≤10 ^10 , 输入给出的a " ,b "为递增顺序。
题解:
正解没想出来,贪心10分,少考虑太多情况了。
正解竟然是二分,万万没想到。想来也满足二分答案的性质,二分出答案后,接下来是 判断答案是否行得通:采用贪心的思想,用靠前的指针尽量指向靠前的目标。
100分代码:
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #ifdef unix #define LL "%lld" #else #define LL "%I64d" #endif using namespace std; const int N=1e5+10; const ll inf=1e15+10; int n,m; bool vis[N]; ll a[N],b[N],link[N]; inline const ll read(){ register ll x=0; register char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar(); return x; } inline bool check(ll mid){ for(ll i=1,j=1,rest,reach;i<=n;i++){ if(a[i]-b[j]>mid) return 0; if(a[i]>b[j]){ rest=mid-(a[i]-b[j]); reach=max(b[j]+rest,a[i]+rest/2); } else reach=a[i]+mid; while(b[j]<=reach&&j<=m) j++; if(j>m) return 1; } return 0; } int main(){ freopen("read.in","r",stdin); freopen("read.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=m;i++) b[i]=read(); ll l=0,r=inf,mid; while(l<r){ mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; } printf(LL,l); return 0; }
T3.柜
【问题背景】
zhx 用一个保险柜藏私房钱。
【问题描述】
zhx 有一个高级的保险柜,是一个使用激光穿过一个有几面镜子的矩形网格的光学封闭机械。当激光被激活后,从矩形网格的最上方一行的左侧水平射入。每当激光束击中一面镜子,/和\二者之一,就会以 45 度角被反射。如果激光束从矩形网格底
部一行的右侧水平射出(见上图左),那么安全检测成功,保险箱打开。否则保险箱发出警报。
保险箱有一面镜子丢失来防止激光束成功穿过网格(见上图右)。zhx 需要开启保险箱时,就将 一 面 镜 子 放到某一个 空 的 网 格 上。因为他知道正确的放镜子
的位置和放置镜子的正确方向(上图右是第 4 行第 3 列,方向是/),因此可以打
开保险箱。 而其他人即使拥有那面镜子也会因为不知道如何安放而无法打开保险箱。
zhx 去陪妹子了,现在需要你帮他确定保险箱是安全的。一个安全的保险箱不会再不插入镜子的情况下打开,并 至 少 存 在 一 个 位置和正确方向的镜子在插入后保险箱能正确打开。
【输入格式】
文件包含多组数据,请读到文件末尾(EOF)结束。
每组数据描述了一个单独的保险箱,开头一行包含了四个整数 R,C,M,N。该机械的网格有R 行 C 列。
接下来有 M 行,每行包含两个整数r " ,c " ,指明有一个/镜子在第r" 行,c" 列。
接下来 N 行以相同方式指明 N 面\镜子的位置。输入数据保证 M+N 面镜子的位置两两不同。
【输出格式】
每组数据对应一行输出,分下列三种情况:
1. 如果不插入镜子保险箱就能被直接打开,输出 0。
2. 如果插入或不插入镜子保险箱都不能被打开,输出-1。
3. 如果保险箱不插入一面镜子就不会被打开,K 是恰好能打开保险箱的插入位置的数量,R,C 是字典序最小的正确插入位置。如果一个位置插入/或\都能正确打开,只算一次。输出三个数,K R C(空格分隔)
【样例输入】
5 6 1 4
2 3
1 2
2 5
4 2
5 5
100 100 0 2
1 77
100 77
100 100 0 0
【样例输出】
2 4 3
0
-1
【数据规模与约定】
对于 5%的数据,满足R,C≤ 4,????,????≤ 4。
对于 25%的数据,满足R,C≤ 100,数据组数≤ 7。
对于另 5%的数据,满足N,M≤ 100。
对于另 5%的数据,满足N+ M≤ 4, 合法位置最多为2,数据组数≤ 32。
对于另15%的数据,满足R,C≤ 7000。
对于另15%的数据,满足N,M≤ 7000。
对于 100%的数据, 满足1 ≤ R,C≤ 10^6 ,1 ≤ N,M≤ 2^5 。 除单独声明的测试点外,数据组数≤ 2,数据有梯度。
题解:
第一遍的做法是枚举镜子的位置然后模拟,应该能得几十分,但就是5分,没改出来。4Kb啊。
60分的做法是正着搜一遍,反着搜一遍,重叠的地方(除镜子所在位置外)就是可以放镜子的地方。
正解树状数组看不懂。
调成5分飞代码(舍不得删):
#include<cstdio> #include<cstring> #include<algorithm> #define pir pair<int,int> using namespace std; const int N=7001; char mp[N][N]; char da[N][N]; int tot,R,C,n,m; pir ans[N]; bool cmp(pir a,pir b){ if(a.first==b.first) return a.second<b.second; return a.first<b.first; } bool go(){ int nowx=1,nowy=0,dir=0,last=0; bool flag=0,sus=0; for(int i=1;i<=C;i++) if(mp[1][i]){ if(mp[1][i]==‘/‘) flag=1; nowy=i;dir=1;break; } for(int i=1;i<=nowy;i++) da[1][i]=1; if(flag||!nowy){puts("-1");return 0;} for(int i,j,tmp;;){ if(dir==0){ tmp=nowy; for(i=nowy+1;i<=C;i++) if(mp[nowx][i]){ nowy=i; dir=mp[i][nowy]==‘/‘?3:1; break; } for(j=tmp;j<=nowy;j++) da[nowx][j]=1; if(nowx==R&&i==C+1){puts("0");return 0;} if(dir==0){ for(j=tmp;j<=C;j++) da[nowx][j]=1; break; } } else if(dir==1){ tmp=nowx; for(i=nowx+1;i<=R;i++) if(mp[i][nowy]){ nowx=i; dir=mp[i][nowy]==‘/‘?2:0; break; } for(j=tmp;j<=nowx;j++) da[j][nowy]=1; if(dir==1){ for(j=tmp;j<=R;j++) da[j][nowy]=1; break; } } else if(dir==2){ tmp=nowy; for(i=nowy-1;i;i--) if(mp[nowx][i]){ nowy=i; dir=mp[i][nowy]==‘/‘?1:3; break; } for(j=tmp;j>=nowy;j--) da[nowx][j]=1; if(dir==2){ for(j=tmp;j;j--) da[nowx][j]=1; break; } } else if(dir==3){ tmp=nowx; for(i=nowx-1;i;i--) if(mp[i][nowy]){ nowx=i; dir=mp[i][nowy]==‘/‘?0:2; break; } for(j=tmp;j>=nowx;j--) da[j][nowy]=1; if(dir==3){ for(j=tmp;j;j--) da[j][nowy]=1; break; } } } return 1; } void repeat(){ tot=0; int nowx=R,nowy=C,dir=0,last=0; for(int i=C;i;i--) if(mp[R][i]){ nowy=i;dir=3;break; } for(int i=C;i>=nowy;i--) da[R][i]+=2; for(int i,j,tmp;;){ if(dir==0){ tmp=nowy; for(i=nowy+1;i<=C;i++) if(mp[nowx][i]){ nowy=i; dir=mp[i][nowy]==‘/‘?3:1; break; } for(j=tmp;j<=nowy;j++) da[nowx][j]+=2; for(j=tmp;j<=nowy;j++) if(da[nowx][j]==3) ans[++tot]=make_pair(nowx,j); if(dir==0){ for(j=tmp;j<=C;j++) da[nowx][j]+=2; for(j=tmp;j<=C;j++) if(da[nowx][j]==3) ans[++tot]=make_pair(nowx,j); break; } } else if(dir==1){ tmp=nowx; for(i=nowx+1;i<=R;i++) if(mp[i][nowy]){ nowx=i; dir=mp[i][nowy]==‘/‘?2:0; break; } for(j=tmp;j<=nowx;j++) da[j][nowy]+=2; for(j=tmp;j<=nowx;j++) if(da[j][nowy]==3) ans[++tot]=make_pair(j,nowy); if(dir==1){ for(j=tmp;j<=R;j++) da[j][nowy]+=2; for(j=tmp;j<=R;j++) if(da[j][nowy]==3) ans[++tot]=make_pair(j,nowy); break; } } else if(dir==2){ tmp=nowy; for(i=nowy-1;i;i--) if(mp[nowx][i]){ nowy=i; dir=mp[i][nowy]==‘/‘?3:1; break; } for(j=tmp;j>=nowy;j--) da[nowx][j]+=2; for(j=tmp;j>=nowy;j--) if(da[nowx][j]==3) ans[++tot]=make_pair(nowx,j); if(dir==2){ for(j=tmp;j;j--) da[nowx][j]+=2; for(j=tmp;j;j--) if(da[nowx][j]==3) ans[++tot]=make_pair(nowx,j); break; } } else if(dir==3){ tmp=nowx; for(i=nowx-1;i;i--) if(mp[i][nowy]){ nowx=i; dir=mp[i][nowy]==‘/‘?0:2; break; } for(j=tmp;j>=nowx;j--) da[j][nowy]+=2; for(j=tmp;j>=nowx;j--) if(da[j][nowy]==3) ans[++tot]=make_pair(j,nowy); if(dir==3){ for(j=tmp;j;j--) da[j][nowy]+=2; for(j=tmp;j;j--) if(da[j][nowy]==3) ans[++tot]=make_pair(j,nowy); break; } } } if(!tot){puts("-1");return ;} sort(ans+1,ans+tot+1,cmp); printf("%d %d %d\n",tot,ans[1].first,ans[1].second); } int main(){ freopen("safe.in","r",stdin); freopen("safe.out","w",stdout); while(scanf("%d%d%d%d",&R,&C,&n,&m)==4){ memset(mp,0,sizeof mp); memset(da,0,sizeof da); for(int i=1,x,y;i<=n;i++) scanf("%d%d",&x,&y),mp[x][y]=‘/‘; for(int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),mp[x][y]=‘\\‘; if(go()) repeat(); } return 0; }
60分模拟代码:
#include<cstdio> #include<cstring> #define N 10010 using namespace std; char map[N][N]; bool vis[N][N]; int n,m,t1,t2,X=N,Y=N,tot; int ax[5]={0,-1,1,0,0}; int ay[5]={0,0,0,-1,1}; int gx1[5]={0,4,3,2,1};//对应反射方向 int gx2[5]={0,3,4,1,2}; bool moni1(){ int x=1,y=1,dir=4; while(1){ vis[x][y]=true; if(map[x][y]==‘1‘) dir=gx1[dir]; if(map[x][y]==‘2‘) dir=gx2[dir]; x+=ax[dir];y+=ay[dir]; if(x==0||x==n+1||y==0||y==m+1)break; } if(((x==n&&y==m+1)||(x==n+1&&y==m))&&dir==4)return true; return false; } void moni2(){ int x=n,y=m,dir=3; while(1){ if(vis[x][y]&&!map[x][y]){ tot++; if(x<X||(x==X&&y<Y)) X=x,Y=y; } if(map[x][y]==‘1‘)dir=gx1[dir]; if(map[x][y]==‘2‘)dir=gx2[dir]; x+=ax[dir];y+=ay[dir]; if(x==0||x==n+1||y==0||y==m+1)break; } } void work(){ for(int i=1,x,y;i<=t1;i++) scanf("%d%d",&x,&y),map[x][y]=‘1‘; for(int i=1,x,y;i<=t2;i++) scanf("%d%d",&x,&y),map[x][y]=‘2‘; if(moni1()){ printf("0\n"); return; } moni2(); if(tot) printf("%d %d %d\n",tot,X,Y); else printf("-1\n"); } int main(){ freopen("safe.in","r",stdin); freopen("safe.out","w",stdout); while(scanf("%d%d%d%d",&n,&m,&t1,&t2)!=EOF){ memset(map,0,sizeof(map)); memset(vis,0,sizeof(vis)); X=N;Y=N;tot=0; work(); } return 0; }
以上是关于1014的主要内容,如果未能解决你的问题,请参考以下文章