题目意思:
数轴上有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>
题目意思:
有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;
}
题目意思:
一只青蛙想到距离为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
*/
题目意思:
求出现次数最多的那个数。如果所有数出现次数都一样且不是全部一样,则输出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;
}
09 hdu 5040 Instrusive
题目意思:
在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;
}