2019HDU多校第十场
(撒花!二十场打完了。虽然题解(riji)咕咕咕了好几场。
1003 Valentine's Day
传送:http://acm.hdu.edu.cn/showproblem.php?pid=6693
题意:每个物品有一个能够快乐的概率$p_i$,问在$n$个物品中选择若干个,能够只快乐一次的最大概率为多少。
数据范围:$1<=n<=10000$。
分析:排序,依此选择最大,次大,……然后什么一个式子就过了?
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e4+100; 4 double p[maxn]; 5 bool cmp(double A,double B) {return A>B;} 6 void rua() 7 { 8 int n;scanf("%d",&n); 9 double ans=0.0,res=0.0,tmp=1.0; 10 for (int i=1;i<=n;i++) scanf("%lf",&p[i]); 11 sort(p+1,p+1+n,cmp); 12 if(p[1]==1.0) {printf("%.12lf\n",p[1]);return;} 13 for (int i=1;i<=n;i++) 14 { 15 double kk=1.0-p[i]; 16 tmp*=kk; 17 double tt=p[i]/kk; 18 res+=tt; 19 ans=max(ans,tmp*res); 20 } 21 printf("%.12lf\n",ans); 22 return; 23 } 24 int main() 25 { 26 int t;scanf("%d",&t); 27 while(t--) rua(); 28 return 0; 29 }
1005 Welcome Party
传送:http://acm.hdu.edu.cn/showproblem.php?pid=6695
题意:有$n$个人,每个人有两个值$a_i,b_i$,每个人只能属于集合A(只参考$a_i$)或集合B(只参考$b_i$),定义每个集合的价值为集合中的最大值。要求求两个集合价值的最小差值。
数据范围:$2<=n<=100000,0<=a_i,b_i<=10^{18}$。
分析:考虑怎么维护最小的差值。对于$a_i$从小到大排序,然后每次枚举集合A的最大值。
假设$a_i$为集合A的最大值,那么在$i$之后的数一定在集合B内,这个最大值可以用过预处理得到。假设这个最大值为$bb$。
那么对于$i$之前的数我们就考虑能不能归到集合B,使得再找到一个更优的答案即可。
如果之前的$b_i<=bb$,对于答案没有贡献。那么我们需要找的是一个数距离$a_i$更近,且大于$bb$。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+10; 5 const ll INF=1e18+10; 6 struct node{ll x,y;}a[maxn]; 7 bool cmp(node p,node q){return p.x<q.x;} 8 set<ll>s; ll mx[maxn]; 9 int main(){ 10 int t,n;scanf("%d",&t); 11 while (t--){ 12 scanf("%d",&n); 13 for (int i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].y); 14 sort(a+1,a+1+n,cmp); 15 ll mxx=0; mx[n+1]=0; 16 for (int i=n;i>=1;i--){ 17 if (a[i].y>mxx) mxx=a[i].y; 18 mx[i]=mxx; 19 } 20 s.clear();ll ans=INF; 21 for (int i=1;i<=n;i++){ 22 ll aa=a[i].x,bb=mx[i+1]; 23 if(i!=n) ans=min(ans,abs(bb-aa)); 24 if(!ans) break; 25 if (bb>aa||s.empty()) {s.insert(a[i].y);continue;} 26 auto it=s.lower_bound(aa); 27 if(it!=s.end()) ans=min(ans,abs((*it)-aa)); 28 if(it!=s.begin()){ 29 --it; 30 ans=min(ans,abs((*it)-aa)); 31 } 32 if(!ans) break; 33 s.insert(a[i].y); 34 } 35 printf("%lld\n",ans); 36 } 37 return 0; 38 }
1009 Block Breaker
传送:http://acm.hdu.edu.cn/showproblem.php?pid=6699
题意:有一个大小为$n*m$的方格矩阵,击打$q$次,问每次击打掉落的块数为多少。每个块掉落的定义为左右至少有一个块不存在,上下至少有一个块不存在。
数据范围:$1<=n,m<=2000,1<=q<=100000$。
分析:开始觉得迷惑为什么大家都会。然后仔细想了想,最多就$n*m$个块会被击落,如果这个块已经不在了,答案就是0,也不会影响到别的块。那么每次就考虑击打一个块能够影响到周围的情况。宽搜就好啦!
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2007; 4 int vis[maxn][maxn]; 5 int n,m,q; 6 int dx[]={0,0,1,-1}; 7 int dy[]={1,-1,0,0}; 8 struct node{int x,y;}; 9 bool check(int x,int y) 10 { 11 int numx=0,numy=0; 12 for (int i=0;i<4;i++) 13 { 14 int xx=x+dx[i],yy=y+dy[i]; 15 if (xx<1 || xx>n || yy<1 || yy>m) continue; 16 if (vis[xx][yy]){ 17 if (i==0 || i==1) numx++; 18 else numy++; 19 } 20 } 21 return (numx>=1 && numy>=1); 22 } 23 24 int bfs(int x,int y) 25 { 26 queue<node> Q; 27 node cur,nex; 28 cur.x=x;cur.y=y; 29 Q.push(cur);vis[x][y]=1; 30 int res=0; 31 while (!Q.empty()) 32 { 33 cur=Q.front();Q.pop(); res++; 34 for (int i=0;i<4;i++) 35 { 36 int xx=cur.x+dx[i],yy=cur.y+dy[i]; 37 if (xx<1 || xx>n || yy<1 || yy>m) continue; 38 if(check(xx,yy) && !vis[xx][yy]) 39 { 40 nex.x=xx;nex.y=yy; 41 Q.push(nex); 42 vis[xx][yy]=1; 43 } 44 } 45 } 46 return res; 47 } 48 void rua() 49 { 50 scanf("%d%d%d",&n,&m,&q); 51 for (int i=0;i<=n;i++) for (int j=0;j<=m;j++) vis[i][j]=0; 52 while (q--) 53 { 54 int x,y;scanf("%d%d",&x,&y); 55 int ans; 56 if(vis[x][y]) ans=0; 57 else ans=bfs(x,y); 58 printf("%d\n",ans); 59 } 60 return; 61 } 62 int main() 63 { 64 int t;scanf("%d",&t); 65 while(t--) rua(); 66 return 0; 67 }
1011 Make Rounddog Happy
题解传送:https://www.cnblogs.com/changer-qyz/p/11392174.html