NOIP2013 DAY2題解
阿新 • • 發佈:2017-10-18
-c med sed tar cnblogs http push printf ati
DAY2
T1積木大賽
傳送門
題目大意:每次可以選區間[l,r]加1,最少選幾次,讓每個位置有
它應有的高度。
題解:O(n)掃一遍就好了。後一個比前一個的高度低,那麽前一個已經把它覆蓋了,
如果高那麽就需要+1了。
代碼:
#include<iostream> #include<cstdio> #define maxn 100009 using namespace std; int n,x,pre,ans; void read(int &x){ char ch=getchar();int f=1;x=0; for(;!isdigit(ch);ch=getchar())ifAC(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘; x*=f; } int main(){ freopen("block.in","r",stdin); freopen("block.out","w",stdout); read(n); for(int i=1;i<=n;i++){ read(x); if(x>pre)ans=ans+x-pre; pre=x; } printf("%d\n",ans); fclose(stdin);fclose(stdout);return 0; }
T2花匠
傳送門
題目大意:求最長波動子序列
題解:貪心
暴力dp[i][1/0][1/0]表示到第i個數作為波峰(1)或波谷(0)選(1)還是不選(0)的最長長度
#include<iostream> #include<cstdio> #include<cstring> #define maxn 100008 using namespace std; int n,h[maxn],dp[maxn][2][2]; void read(int &x){ char ch=getchar();x=0;int f=1; for70(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘; x=x*f; } int main(){ read(n); for(int i=1;i<=n;i++)read(h[i]); dp[1][1][1]=dp[1][0][1]=1; for(int i=2;i<=n;i++){ for(int j=1;j<i;j++){ if(h[i]>h[j])dp[i][1][1]=max(dp[i][1][1],dp[j][0][1]+1); if(h[i]<h[j])dp[i][0][1]=max(dp[i][0][1],dp[j][1][1]+1); dp[i][0][0]=dp[i][1][0]=max(max(dp[j][0][1],dp[j][0][0]),max(dp[j][1][0],dp[j][1][1])); } } printf("%d\n",max(max(dp[n][1][1],dp[n][1][0]),max(dp[n][0][1],dp[n][0][0]))); return 0; }
這不跟昨天湖南的題一樣麽。
對於 5 4 3 2 9
5 2 9,4 2 9,3 2 9,好像沒什麽區別。那麽連續遞減的5 4 3 2就可以看成一個數了。
以一個數為大的和小的分別掃一遍就好。
#include<iostream> #include<cstdio> #include<cstring> #define maxn 100008 using namespace std; int ans,ret,cur,flag,n,h[maxn]; void read(int &x){ char ch=getchar();x=0;int f=1; for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘; x=x*f; } int main(){ freopen("flower.in","r",stdin); freopen("flower.out","w",stdout); read(n); for(int i=1;i<=n;i++)read(h[i]); cur=h[1];ans=1; for(int i=2;i<=n;i++){ if(flag){ if(h[i]<cur)flag=0,ans++,cur=h[i]; else cur=max(cur,h[i]); }else{ if(h[i]>cur)flag=1,ans++,cur=h[i]; else cur=min(cur,h[i]); } } cur=h[1];ret=1;flag=0; for(int i=2;i<=n;i++){ if(flag){ if(h[i]>cur)flag=0,ret++,cur=h[i]; else cur=min(cur,h[i]); }else{ if(h[i]<cur)flag=1,ret++,cur=h[i]; else cur=max(cur,h[i]); } } ans=max(ans,ret); printf("%d\n",ans); fclose(stdin);fclose(stdout); return 0; }AC
一個多月前我做的...似乎是看了就是看了題解...
#include<iostream> #include<cstdio> using namespace std; int n,pre,now,r=1,d=1; int main() { scanf("%d",&n); scanf("%d",&pre);//當前這盆花前面那盆花的高度,初始為第一盆花的高度。 for(int i=1;i<n;i++) { scanf("%d",&now); if(now>pre)r=max(r,d+1);//當前這盆花高度大於前面那盆花高度 if(now<pre)d=max(d,r+1);//說明現在是上升序列,就要求出到Now這個花盆且波動為 pre=now; //上升的最優解,就從原來求出的最後波動為上升的最優解, } //(也就是說此時當前這盆花不加入之前最優解,移走) printf("%d",max(r,d));//和從最後波動為下降的最優解+1選取最優值(不移走)。 return 0; }AC
T3華容道
傳送門
題目大意:一個n*m的矩陣,有n*m-1個棋子。1表示該棋子能移動,0表示不能。
給出指定位置和目標位置。求最少幾步能利用空白格子將指定位置棋子移到目標位置。
題解:
dfs 5分...懷疑人生
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define inf 100000000 using namespace std; int n,m,q,x,cnt,ans; int ex,ey,sx,sy,tx,ty; int t[40][40],tmp[40][40],vis[40][40]; int mx[4]={0,1,-1,0}, my[4]={-1,0,0,1}; void read(int &x){ char ch=getchar();x=0;int f=1; for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘; x=x*f; } void dfs(int ex,int ey,int sx,int sy,int tx,int ty,int prex,int prey,int ste){ if(ex==tx&&ey==ty&&abs(sx-ex)+abs(sy-ey)<=1){ ans=min(ans,ste+1); return; } for(int i=0;i<4;i++){ int xx=ex+mx[i],yy=ey+my[i]; if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&t[xx][yy]&&(xx!=prex||yy!=prey)&&!vis[xx][yy]){ vis[xx][yy]=true; if(xx==sx&&yy==sy){ dfs(xx,yy,ex,ey,tx,ty,ex,ey,ste+1); }else dfs(xx,yy,sx,sy,tx,ty,ex,ey,ste+1); } } } int main(){ // freopen("puzzle.in","r",stdin); // freopen("puzzle.out","w",stdout); read(n);read(m);read(q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(t[i][j]); for(int i=1;i<=q;i++){ cnt=0;ans=inf; memset(vis,0,sizeof(vis)); read(ex);read(ey);//空白格子 vis[ex][ey]=true; read(sx);read(sy);//指定棋子 read(tx);read(ty);//目標位置 if(sx==tx&&sy==ty){ printf("0\n"); continue; } dfs(ex,ey,sx,sy,tx,ty,0,0,0); if(ans==inf)printf("-1\n"); else printf("%d\n",ans); } // fclose(stdin);fclose(stdout); return 0; }5
bfs 70 其實考試時開始寫的bfs。發現不會記錄狀態。
看了題解算來只需要記錄空白格子和指定棋子的位置就好了。
時間復雜度O(q*(nm)^2)
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; int ans,n,m,qx,tx,ty; int t[40][40],vis[40][40][40][40]; int mx[4]={0,1,0,-1}, my[4]={-1,0,1,0}; struct Node{ int ex,ey,sx,sy,ste; }now; queue<Node>q; void read(int &x){ char ch=getchar();x=0;int f=1; for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘; x=x*f; } void BFS(){ memset(vis,0,sizeof(vis)); Node tmp,cur; vis[now.sx][now.sy][now.ex][now.ey]=true; while(!q.empty())q.pop();q.push(now); while(!q.empty()){ cur=q.front();q.pop(); if(cur.sx==tx&&cur.sy==ty){ ans=cur.ste; return; } for(int i=0;i<4;i++){ tmp=cur; int xx=tmp.ex+mx[i],yy=tmp.ey+my[i]; if(!t[xx][yy]||xx<1||xx>n||yy<1||yy>m)continue; if(xx==tmp.sx&&yy==tmp.sy)tmp.sx=tmp.ex,tmp.sy=tmp.ey; tmp.ex=xx;tmp.ey=yy;tmp.ste=cur.ste+1; if(!vis[tmp.sx][tmp.sy][tmp.ex][tmp.ey]){ vis[tmp.sx][tmp.sy][tmp.ex][tmp.ey]=true; q.push(tmp); } } } } int main(){ read(n);read(m);read(qx); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(t[i][j]); for(;qx;qx--){ read(now.ex);read(now.ey);read(now.sx);read(now.sy);read(tx);read(ty); now.ste=0;ans=n*m; BFS(); if(ans!=n*m)printf("%d\n",ans); else printf("-1\n"); } return 0; }70
正解..搜索+最短路。傻逼錯誤毀我青春...從下午寫到現在...
我還是單獨開個隨筆講這個題吧。邪王真眼
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define maxn 5000 #define inf 2147483647 int n,m,qx,sumedge,ans,ex,ey,sx,sy,tx,ty,p; int map[40][40],pre_dis[40][40],head[maxn],vis[maxn],dis[maxn]; int mx[4]={-1,0,1,0}, my[4]={0,1,0,-1}; struct Node{ int x,y; }cur,nxt; queue<Node>q; queue<int>qn; struct Edge{ int x,y,z,nxt; Edge(int x=0,int y=0,int z=0,int nxt=0): x(x),y(y),z(z),nxt(nxt){} }edge[maxn]; void add(int x,int y,int z){ edge[++sumedge]=Edge(x,y,z,head[x]); head[x]=sumedge; } int get_id(int i,int j){ return (i-1)*m*4+(j-1)*4; } void bfs(int ex,int ey,int sx,int sy,int d){ memset(pre_dis,-1,sizeof(pre_dis)); pre_dis[ex][ey]=0;pre_dis[sx][sy]=1; Node now,nxt;now.x=ex;now.y=ey; while(!q.empty())q.pop(); q.push(now); while(!q.empty()){ now=q.front();q.pop(); int x=now.x,y=now.y; for(int i=0;i<4;i++){ int xx=x+mx[i],yy=y+my[i]; if(xx<1||xx>n||yy<1||yy>m||!map[xx][yy]||pre_dis[xx][yy]!=-1)continue; pre_dis[xx][yy]=pre_dis[x][y]+1; nxt.x=xx;nxt.y=yy; q.push(nxt); } } if(d==4)return; int id=get_id(sx,sy); for(int i=0;i<4;i++) if(pre_dis[sx+mx[i]][sy+my[i]]>0) add(id+d,id+i,pre_dis[sx+mx[i]][sy+my[i]]); add(id+d,get_id(ex,ey)+(d+2)%4,1); } void spfa(int sx,int sy){ memset(dis,-1,sizeof(dis)); memset(vis,0,sizeof(vis)); while(!qn.empty())qn.pop(); int id=get_id(sx,sy); for(int i=0;i<4;i++) if(pre_dis[sx+mx[i]][sy+my[i]]!=-1){ dis[id+i]=pre_dis[sx+mx[i]][sy+my[i]]; qn.push(id+i); } while(!qn.empty()){ int cur=qn.front();qn.pop();vis[cur]=false; for(int i=head[cur];i;i=edge[i].nxt){ int v=edge[i].y; if(dis[v]>dis[cur]+edge[i].z||dis[v]==-1){ dis[v]=dis[cur]+edge[i].z; if(!vis[v]){ vis[v]=true; qn.push(v); } } } } } int main(){ scanf("%d%d%d",&n,&m,&qx); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&map[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]){ if(map[i-1][j])bfs(i-1,j,i,j,0); if(map[i][j+1])bfs(i,j+1,i,j,1); if(map[i+1][j])bfs(i+1,j,i,j,2); if(map[i][j-1])bfs(i,j-1,i,j,3); } for(int i=1;i<=qx;i++){ scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty); if(sx==tx&&sy==ty){ printf("0\n"); continue; } bfs(ex,ey,sx,sy,4); ans=inf; spfa(sx,sy); int id=get_id(tx,ty); for(int j=0;j<4;j++) if(dis[id+j]!=-1)ans=min(ans,dis[id+j]); if(ans==inf) ans=-1; printf("%d\n",ans); } return 0; }AC
NOIP2013 DAY2題解