02 hdu 5033 Building
题目意思:
数轴上有n根柱子,每根柱子有个位置坐标和高度,有q个询问,询问从位置qi能看到的角度(保证左右至少有一个柱子)
解题思路:
单调栈维护一个凸性柱子序列。
离线处理所有的查询,排序,然后扫一遍qi,把柱子插进去,更新单调栈。注意查询位置也要更新栈。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 110000 struct Inf { double xi,hi; }inf[Maxn]; int n,q,L[Maxn],R[Maxn],sta[Maxn]; struct Sa { double xi; int pos; }sa[Maxn]; double be[Maxn]; bool cmp1(struct Inf a,struct Inf b) { return a.xi<b.xi; //return a.hi<b.hi; } bool cmp2(struct Sa a,struct Sa b) { return a.xi<b.xi; } bool iscan(int top,int topp,int la) { if(((inf[top].hi-inf[la].hi)/(inf[la].xi-inf[top].xi))<=((inf[topp].hi-inf[top].hi)/(inf[top].xi-inf[topp].xi))) return true; return false; } bool iscan1(int top,int topp,int la) { if(((inf[top].hi-inf[la].hi)/(inf[top].xi-inf[la].xi))<=((inf[topp].hi-inf[top].hi)/(inf[topp].xi-inf[top].xi))) return true; return false; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); for(int nn=1;nn<=t;nn++) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf",&inf[i].xi,&inf[i].hi); sort(inf+1,inf+n+1,cmp1); scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%lf",&sa[i].xi); be[i]=sa[i].xi; sa[i].pos=i; } sort(sa+1,sa+q+1,cmp2); int cnt=0; int la=1; for(int i=1;i<=q;i++) { while(inf[la].xi<sa[i].xi&&la<=n) { if(!cnt) { sta[++cnt]=la; la++; } else if(cnt==1) { if(inf[la].hi>=inf[sta[cnt]].hi) sta[cnt]=la; else sta[++cnt]=la; la++; } else { int top=sta[cnt]; int topp=sta[cnt-1]; while(inf[top].hi<=inf[la].hi||iscan(top,topp,la)) { --cnt; if(cnt<=1) break; top=sta[cnt]; topp=sta[cnt-1]; } if(cnt<=1) { if(!cnt) sta[++cnt]=la; else { if(inf[la].hi>=inf[sta[cnt]].hi) sta[cnt]=la; else sta[++cnt]=la; } } else sta[++cnt]=la; ++la; } } if(cnt==1) //最少有一个 { L[sa[i].pos]=sta[cnt]; continue; } int top=sta[cnt]; int topp=sta[cnt-1]; while((inf[top].hi/(sa[i].xi-inf[top].xi))<=((inf[topp].hi-inf[top].hi)/(inf[top].xi-inf[topp].xi))) { cnt--; if(cnt<=1) break; top=sta[cnt]; topp=sta[cnt-1]; } L[sa[i].pos]=sta[cnt]; } cnt=0; la=n; for(int i=q;i>=1;i--) { while(inf[la].xi>sa[i].xi&&la>=1) { if(!cnt) { sta[++cnt]=la; la--; } else if(cnt==1) { if(inf[la].hi>=inf[sta[cnt]].hi) sta[cnt]=la; else sta[++cnt]=la; la--; } else { int top=sta[cnt]; int topp=sta[cnt-1]; while(inf[top].hi<=inf[la].hi||iscan1(top,topp,la)) { --cnt; if(cnt<=1) break; top=sta[cnt]; topp=sta[cnt-1]; } if(cnt<=1) { if(!cnt) sta[++cnt]=la; else { if(inf[la].hi>=inf[sta[cnt]].hi) sta[cnt]=la; else sta[++cnt]=la; } } else sta[++cnt]=la; la--; } } if(cnt==1) //最少有一个 { R[sa[i].pos]=sta[cnt]; continue; } int top=sta[cnt],topp=sta[cnt-1]; while((inf[top].hi/(inf[top].xi-sa[i].xi))<((inf[topp].hi-inf[top].hi)/(inf[topp].xi-inf[top].xi))) { cnt--; if(cnt<=1) break; top=sta[cnt]; topp=sta[cnt-1]; } R[sa[i].pos]=sta[cnt]; } printf("Case #%d:\n",nn); for(int i=1;i<=q;i++) { int ri=R[i],le=L[i]; //printf("le:%d ri:%d\n",le,ri); double px=inf[ri].xi-be[i],py=inf[ri].hi; double qx=inf[le].xi-be[i],qy=inf[le].hi; double temp=px*qx+py*qy; printf("%.10f\n",acos(temp/(sqrt(px*px+py*py)*sqrt(qx*qx+qy*qy)))/PI*180.0); } } return 0; } <span style="color:#ff0000;"> </span>
05 hdu 5036 Explosion
题目意思:
有n扇门,每扇门里面有一些开其他门的钥匙,如果所有的门都不能开,需要炸开一些门,求把所有的门打开需要炸弹个数的期望。
解题思路:
首先要把问题给抽象出来。然后用位来处理加快速度。一个整数32位,这样1000的数据量用位来处理相当于1000/32的数据量。
考虑每个点需要用炸弹打开的概率,那么所有点的概率之和就是解。每个点 v 需要用炸弹打开的概率是 1/S, S是u(u->v联通)的数量,然后就变成求这个图的传递闭包了,用bitset优化。为什么是1/S呢,因为这S个门里面必定要用一个炸弹砸开,而砸v的概率为1/S。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1100 bitset<Maxn>myb[Maxn]; //myb[i]表示i能开的门 int n; double solve() { double ans=0; for(int i=1;i<=n;i++) // { for(int j=1;j<=n;j++) //用1000个bit处理时间相当于1000/32个整数 { if(myb[j][i]) //j能开i myb[j]|=myb[i]; //则j能开的门数要加上i能开的门苏 } } for(int i=1;i<=n;i++) { int nu=0; for(int j=1;j<=n;j++) if(myb[j][i]) nu++; ans+=1.0/nu; } return ans; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,cnt=0; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) { myb[i].reset(); myb[i][i]=1; //自己可以开自己 } for(int i=1;i<=n;i++) { int nu; scanf("%d",&nu); for(int j=1;j<=nu;j++) { int temp; scanf("%d",&temp); myb[i][temp]=1; } } printf("Case #%d: %.5f\n",++cnt,solve()); } return 0; }
06 hdu 5037 Frog
题目意思:
一只青蛙想到距离为m的河对岸去,河中间有n块石头,告诉每块石头的位置,青蛙每次最多只能跳l距离,求怎样放石头,使得青蛙跳到对岸的步数最大,求这个步数。
解题思路:
贪心
注意青蛙肯定是每次尽可能跳,能跳远的肯定不会跳近的。尽可能的放置l+1的连续三块石头,这样青蛙两步只能走l+1.
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 220000 int sa[Maxn]; int n,m,l; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); for(int cnt=1;cnt<=t;cnt++) { scanf("%d%d%d",&n,&m,&l); for(int i=1;i<=n;i++) scanf("%d",&sa[i]); sort(sa+1,sa+n+1); n=unique(sa+1,sa+n+1)-sa-1; sa[++n]=m; int la=l,ans=0; sa[0]=0; for(int i=1;i<=n;i++) { ans+=(sa[i]-sa[i-1])/(l+1)*2; int mod=(sa[i]-sa[i-1])%(l+1); if(mod+la>=l+1) { ans++; la=mod; } else la+=mod; } printf("Case #%d: %d\n",cnt,ans); } return 0; } /* 0 4 3 5 14 2 2 2 2 9 5 1 10 5 2 1 7 5 2 */
07 hdu 5038 Grade
题目意思:
求出现次数最多的那个数。如果所有数出现次数都一样且不是全部一样,则输出Bad Mushroom
解题思路:
水题,排序就行。
代码:
</pre><pre name="code" class="cpp">//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1100000 int sa[Maxn],n; struct Inf { int va,ti; }inf[Maxn]; int nu; bool cmp(struct Inf a,struct Inf b) { if(a.ti!=b.ti) return a.ti>b.ti; return a.va<b.va; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); for(int cnt=1;cnt<=t;cnt++) { scanf("%d",&n); for(int i=1;i<=n;i++) { int temp; scanf("%d",&temp); sa[i]=10000-(100-temp)*(100-temp); } sort(sa+1,sa+n+1); nu=0; inf[++nu].va=sa[1]; inf[nu].ti=1; int la=sa[1]; for(int i=2;i<=n;i++) { if(sa[i]==la) { inf[nu].ti++; la=sa[i]; } else { ++nu; inf[nu].va=sa[i]; inf[nu].ti=1; la=sa[i]; } } sort(inf+1,inf+nu+1,cmp); printf("Case #%d:\n",cnt); if(inf[nu].ti==inf[1].ti&&nu!=1) { printf("Bad Mushroom\n"); continue; } int ti=inf[1].ti; printf("%d",inf[1].va); for(int i=2;i<=nu&&inf[i].ti==ti;i++) printf(" %d",inf[i].va); putchar('\n'); } return 0; }
题目意思:
在n*n的格子里,有标有方向的摄像机,摄像机能辐射出去一个格子(包括自己共两个格子,坑点),摄像机每秒钟顺时针旋转90度。‘#’不能走,‘.'可以走。求从’M'到‘T'的最短时间。如果此刻被照或此刻下一格子被照,则到下一格子需花费三秒,否则花费一秒。
解题思路:
BFS
预处理出lig[Maxn][Maxn][5]; //lig[x][y][i]表示格子(x,y)在4*i秒时是否照亮
vis[Maxn][Maxn][5]; //vis[x][y][i]表示格子(x,y)在4*i秒时是否被访问了
然后就是裸地BFS了,按时间优先。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 550 char sa[Maxn][Maxn]; bool lig[Maxn][Maxn][5]; //lig[x][y][i]表示格子(x,y)在4*i秒时是否照亮 int n,dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; int bx,by,ex,ey,vis[Maxn][Maxn][5]; //vis[x][y][i]表示格子(x,y)在4*i秒时是否被访问了 struct Inf { int x,y; int ti; friend bool operator < (Inf a,Inf b) //时间优先 { return a.ti>b.ti; } }; bool iscan(int x,int y) { if(x<1||x>n||y<1||y>n) return false; return true; } int jud(char c) //判断方向 { if(c=='N') return 0; if(c=='E') return 1; if(c=='S') return 2; if(c=='W') return 3; return -1; } int bfs() { priority_queue<Inf>myq; Inf st; st.x=bx,st.y=by,st.ti=0; vis[st.x][st.y][0]=true; myq.push(st); while(!myq.empty()) { Inf cur; cur=myq.top(); myq.pop(); //printf("x:%d y:%d ti:%d\n",cur.x,cur.y,cur.ti); if(cur.x==ex&&cur.y==ey) return cur.ti; bool fl=lig[cur.x][cur.y][cur.ti%4]; if(!vis[cur.x][cur.y][(cur.ti+1)%4]) //停一秒 { Inf ne=cur; ne.ti+=1; vis[ne.x][ne.y][ne.ti%4]=true; myq.push(ne); } for(int i=0;i<4;i++) { int x=cur.x+dir[i][0],y=cur.y+dir[i][1]; if(!iscan(x,y)||sa[x][y]=='#') continue; Inf ne; ne.x=x,ne.y=y,ne.ti=(fl||lig[x][y][cur.ti%4])?(cur.ti+3):(cur.ti+1);//看是走3秒还是一秒 if(vis[x][y][ne.ti%4]) continue; vis[x][y][ne.ti%4]=true; myq.push(ne); } } return -1; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); for(int cnt=1;cnt<=t;cnt++) { scanf("%d",&n); memset(lig,false,sizeof(lig)); memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) { scanf("%s",sa[i]+1); for(int j=1;j<=n;j++) { if(sa[i][j]=='M') { bx=i,by=j; continue; } if(sa[i][j]=='T') { ex=i,ey=j; continue; } int du=jud(sa[i][j]); if(du==-1) continue; for(int k=0;k<4;k++) //初始化格子被照亮情况 { lig[i][j][k]=true; int x=i,y=j; x+=dir[du][0],y+=dir[du][1]; if(!iscan(x,y)) break; lig[x][y][k]=true; du=(du+1)%4; } } } printf("Case #%d: %d\n",cnt,bfs()); } return 0; }