近期离线赛真题T3
来源:互联网 发布:淘宝客 链接 内部跳转 编辑:程序博客网 时间:2024/05/19 17:26
总之考试时基本上是可以A掉的啦
NOIP2012 Day2 T3 疫情控制
分析
无法控制疫情的情况:军队数小于第二层节点数
二分是必然的。
然后贪心向上也是可以明显看出的。
问题就转换为了有哪些点需要通过根节点到另一个第二层节点上。
考虑所有能到达首都的军队,记录他们上来的位置以及其余剩的时间。
然后DFS求出仍需驻扎军队的第二层节点与其到根节点的距离。
那么问题就转换为一个二分图匹配 经测试直接跑二分图匹配理论40实际90
不过这个二分图匹配是可以贪心的,
排序+堆,特判回到原节点就能通过了。
复杂度为
因为调用了系统堆导致跑得慢。
std中采用预留的方法来去掉回原节点的情况,就可以排序贪心了。
代码
#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}#define M 50004#define Mk 16int n,m;int Next[M<<1],V[M<<1],W[M<<1],Head[M],tot;int Pos[M],Cnt,MxSe;void Add_Edge(int u,int v,int w){ Next[++tot]=Head[u],V[Head[u]=tot]=v,W[tot]=w;}#define LREP(i,A) for(int i=Head[A];i;i=Next[i])int Fa[M][Mk],Fr[M];LL Sum[M][Mk],Dis[M],L,R,Ans;void DFS(int A,int f,int From){ Fr[A]=From; int B; LREP(i,A)if((B=V[i])!=f){ Fa[B][0]=A; Sum[B][0]=W[i]; Dis[B]=Dis[A]+W[i]; DFS(B,A,From); }}struct Node{ int w,x; bool operator <(const Node &_)const{ return w==_.w?x<_.x:w>_.w; }};set<Node>S;bool Mark[M];bool Find(int A,int f){ if(Mark[A])return 1; bool Res=1; int Son=0,B; LREP(i,A)if((B=V[i])!=f){ if(!Find(B,A))return 0; Son++; } return Son!=0;}int Tmp[M];LL Less[M];bool Cmp(int a,int b){return Less[a]<Less[b];}bool Check(LL Tim){ memset(Mark,0,sizeof(Mark)); int Num=0; REP(i,0,m){ int A=Pos[i]; if(Dis[A]>Tim){ LL Tmp=0; DREP(k,Mk-1,-1) if(Tmp+Sum[A][k]<=Tim){ Tmp+=Sum[A][k]; A=Fa[A][k]; } Mark[A]=1; } else{ Tmp[Num++]=A; Less[A]=Tim-Dis[A]; } } S.clear(); LREP(i,1){ int B=V[i]; if(!Find(B,1))S.insert((Node){Dis[B],B}); } if(Num<S.size())return 0; if(S.empty())return 1; REP(i,0,Num){ int A=Tmp[i]; if(Dis[A]<=Tim){ int f=Fr[A]; LL Les=Less[A]; set<Node>::iterator it,jt; if(Les>=(*S.begin()).w) it=S.begin(); else{ it=S.lower_bound((Node){Les,0}); if((jt=S.find((Node){Dis[f],f}))!=S.end()) if(it==S.end() || (*it).w<Dis[f]) it=jt; } if(it!=S.end())S.erase(it); } if(S.empty())return 1; } return S.empty();}void Init(){ REP(k,1,Mk) REP(i,1,n+1){ int j=Fa[i][k-1]; Fa[i][k]=Fa[j][k-1]; Sum[i][k]=Sum[i][k-1]+Sum[j][k-1]; }}int main(){ Rd(n); REP(i,1,n){ int u,v,w; Rd(u),Rd(v),Rd(w); Add_Edge(u,v,w); Add_Edge(v,u,w); if(v==1 || u==1)Cnt++; } Rd(m); REP(i,0,m)Rd(Pos[i]); if(m<Cnt){ puts("-1"); return 0; } LREP(i,1){ int B=V[i]; Fa[B][0]=1; Dis[B]=Sum[B][0]=W[i]; DFS(B,1,B); chkmax(MxSe,W[i]); } REP(i,0,m)chkmax(R,Dis[Pos[i]]); R+=MxSe; Fa[1][0]=1; Init(); while(L<=R){ LL Mid=L+R>>1; if(Check(Mid))Ans=Mid,R=Mid-1; else L=Mid+1; } printf("%lld\n",Ans); return 0;}
NOIP2013 Day2 华容道
分析
P60(P70)
容易想到把空格和目标棋子的坐标来作为下标维度来搜索。
简单的BFS就可以完成这种情况下的求解,复杂度为
P100
显然对于
注意到每次询问时整个地图的障碍位置是不变的,
而目标棋子移动一位必须要有空格在其四周的一个方向。
预处理出目标棋子在每个可行位置,
空格从其四周某个方向移动到另一个方向的所需步数。
BFS完成,复杂度为
然后对于每个询问,先处理出空格移动到目标棋子四个方向的步数。
然后从其开始求最短路,此时点数为
Dij或SPFA均可顺利通过。
代码
#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}#define M 31int n,m,C[M][M],q;bool Check(int x,int y){ return x>0 && y>0 && x<=n && y<=m && C[x][y];}int Xr[]={1,0,0,-1},Yr[]={0,1,-1,0};struct P60{ int Dis[M][M][M][M]; int ex,ey,sx,sy,tx,ty; struct Node{ int ex,ey,sx,sy; }; queue<Node>Q; void Solve(){ while(q--){ Rd(ex),Rd(ey),Rd(sx),Rd(sy),Rd(tx),Rd(ty); memset(Dis,-1,sizeof(Dis)); while(!Q.empty())Q.pop(); Dis[ex][ey][sx][sy]=0; Q.push((Node){ex,ey,sx,sy}); bool Flag=0; while(!Q.empty()){ Node T=Q.front();Q.pop(); int X1=T.ex,Y1=T.ey,X2=T.sx,Y2=T.sy; int u=Dis[X1][Y1][X2][Y2]; if(X2==tx && Y2==ty){ printf("%d\n",u); Flag=1; break; } REP(g,0,4){ int pex=X1+Xr[g],pey=Y1+Yr[g],psx=X2,psy=Y2; if(!Check(pex,pey))continue; if(pex==X2 && pey==Y2)psx=X1,psy=Y1; int &Pos=Dis[pex][pey][psx][psy]; if(Pos==-1){ Pos=u+1; Q.push((Node){pex,pey,psx,psy}); } } } if(!Flag)puts("-1"); } }}P60;struct P100{ int Len[M][M][4][4];//4,4:原来空格的方向,现在空格的方向。 int Dis[M][M]; int Ans[M][M][4]; bool No[M][M]; int Qx[M*M],Qy[M*M]; void BFS(int sx,int sy){ int l,r; l=r=0; memset(Dis,-1,sizeof(Dis)); Dis[sx][sy]=0; Qx[r]=sx,Qy[r++]=sy; while(l<r){ int X1=Qx[l],Y1=Qy[l++]; REP(g,0,4){ int X2=X1+Xr[g],Y2=Y1+Yr[g]; if(!Check(X2,Y2) || No[X2][Y2])continue; if(Dis[X2][Y2]==-1){ Dis[X2][Y2]=Dis[X1][Y1]+1; Qx[r]=X2,Qy[r++]=Y2; } } } } void Init(){ memset(Len,-1,sizeof(Len)); REP(x,1,n+1) REP(y,1,m+1){ if(!Check(x,y))continue; No[x][y]=1; REP(g,0,4){ int px=x+Xr[g],py=y+Yr[g]; if(!Check(px,py))continue; BFS(px,py); REP(k,0,4){ int xp=x+Xr[k],yp=y+Yr[k]; if(!Check(xp,yp))continue; if(Dis[xp][yp]==-1)continue; Len[x][y][g][k]=Dis[xp][yp]; } } No[x][y]=0; } } int ex,ey,sx,sy,tx,ty; struct Node{ int x,y,p,w; bool operator <(const Node &_)const{ return w>_.w; } }; priority_queue<Node>Q; void Solve(){ Init(); while(q--){ Rd(ex),Rd(ey),Rd(sx),Rd(sy),Rd(tx),Rd(ty); if(sx==tx && sy==ty){ puts("0"); continue; } No[sx][sy]=1; BFS(ex,ey); No[sx][sy]=0; while(!Q.empty())Q.pop(); memset(Ans,63,sizeof(Ans)); REP(g,0,4){ int px=sx+Xr[g],py=sy+Yr[g]; if(!Check(px,py))continue; if(Dis[px][py]!=-1){ Ans[sx][sy][g]=Dis[px][py]; Q.push((Node){sx,sy,g,Dis[px][py]}); } } bool Flag=0; while(!Q.empty()){ Node T=Q.top();Q.pop(); int x=T.x,y=T.y,p=T.p,w=T.w; if(w!=Ans[x][y][p])continue; if(x==tx && y==ty){ printf("%d\n",w); Flag=1; break; } REP(g,0,4){ if(Len[x][y][p][g]==-1)continue; int px=x+Xr[g],py=y+Yr[g],pp=3-g,Cost=w+Len[x][y][p][g]+1; if(Cost<Ans[px][py][pp]){ Ans[px][py][pp]=Cost; Q.push((Node){px,py,pp,Cost}); } } } if(!Flag)puts("-1"); } }}P100;int main(){ Rd(n),Rd(m),Rd(q); REP(i,1,n+1) REP(j,1,m+1) Rd(C[i][j]); if(q<=10)P60.Solve(); else P100.Solve(); return 0;}
NOIP2015 Day1 T3 斗地主
这道破题的题意十分鬼畜超越了普通斗地主的玩法 所幸数据很良心并没有什么特别的情况
分析
看这个数据范围和保证随机,
说明这是一道搜索题。
然后因为这道题的牌型很多,分类考虑。
定义
所需的最小步数。
那么状态数很小,然后转移起来比较简单。
稍微注意一下拆掉对子三张四张的情况。
剩下的就枚举顺子连对之类的东西然后直接DFS吧。
速度很快。
另:似乎机房没有人写DP..
代码
如果把王炸当对子(原题就这么打的)算的话把那些多余的东西删掉即可。
#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long long#define INF 0x3f3f3f3fint T,n,P[16];int F[24][24][24][24];void Init(){ memset(F,63,sizeof(F)); F[0][0][0][0]=0; REP(l,0,8) REP(k,0,10) REP(j,0,18) REP(i,0,18){ int &Now=F[i][j][k][l]; if(i) chkmin(Now,F[i-1][j][k][l]+1); if(j) chkmin(Now,F[i][j-1][k][l]+1); if(k) chkmin(Now,F[i][j][k-1][l]+1); if(l) chkmin(Now,F[i][j][k][l-1]+1); if(k && i) chkmin(Now,F[i-1][j][k-1][l]+1); if(k && j) chkmin(Now,F[i][j-1][k-1][l]+1); if(l && i>=2) chkmin(Now,F[i-2][j][k][l-1]+1); if(l && j>=2) chkmin(Now,F[i][j-2][k][l-1]+1); if(j) chkmin(Now,F[i+2][j-1][k][l]);//拆对子 if(k) chkmin(Now,F[i+1][j+1][k-1][l]);//拆三张 if(l) chkmin(Now,F[i+1][j][k+1][l-1]);//拆炸弹 if(l) chkmin(Now,F[i][j+2][k][l-1]); }}int Ans;void Solve(int Type,int S){ if(S>Ans)return; int Cnt[6]; memset(Cnt,0,sizeof(Cnt)); REP(i,0,15)Cnt[P[i]]++; chkmin(Ans,F[Cnt[1]][Cnt[2]][Cnt[3]][Cnt[4]]+S); if(Type<=1){ REP(i,3,14){ int j=i,len=0; while(j<15 && P[j]>=3){ P[j++]-=3,len++; if(len>=2)Solve(1,S+1); } REP(k,i,j)P[k]+=3; } } if(Type<=2){ REP(i,3,13){ int j=i,len=0; while(j<15 && P[j]>=2){ P[j++]-=2,len++; if(len>=3)Solve(2,S+1); } REP(k,i,j)P[k]+=2; } } if(Type<=3){ REP(i,3,11){ int j=i,len=0; while(j<15 && P[j]>=1){ P[j++]--,len++; if(len>=5)Solve(3,S+1); } REP(k,i,j)P[k]++; } }}int main(){ scanf("%d %d",&T,&n); Init(); while(T--){ memset(P,0,sizeof(P)); REP(i,0,n){ int a,b; scanf("%d %d",&a,&b); if(a==1)a=14; if(a==0)a=b-1; P[a]++; } Ans=INF; Solve(1,0); int Res=Ans; if(P[0] && P[1]){ P[0]=P[1]=0; Ans=INF; Solve(1,0); chkmin(Res,Ans+1); } printf("%d\n",Res); } return 0;}
2017-10-26.RT..
- 近期离线赛真题T3
- 近期离线赛总结
- T3
- t3
- T3
- T3
- t3
- t3
- 近期。
- 近期
- 近期
- 近期
- 近期
- 近期
- 近期
- 近期
- 特色t3
- T3定时器
- maven打jar包
- 如何用python对文本进行操作
- mysql处理高并发,防止库存超卖
- 给出一百分制成绩,要求输出成绩等级'A',要求输出成绩等级 ‘A’'B''C''D''E',90分以上为A,80-89为B,70-79为C,69-69 为D,60分以下为E。*/
- Android 全屏模式下,解决 软键盘遮挡
- 近期离线赛真题T3
- [机器学习]PCA主成分分析原理分析和Matlab实现方法
- Difference Between Cisco GLC-T and GLC-TE
- Clang-Format格式化选项介绍
- 别担心找不到切换用户的按钮
- 正确率 召回率和F值
- BST的实现
- C/C++基础面试集锦(一)strcpy、memcpy
- FFTW3在VS环境下的安装(亲测)