zoukankan      html  css  js  c++  java
  • 2014ACM/ICPC亚洲区北京站 上交命题

    http://acm.hdu.edu.cn/showproblem.php?pid=5112

    输入n个时刻和位置,问那两个时刻间速度最快。

    解法:按照时间排序,然后依次求相邻两个之间的速度,速度=ds/dt

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=1e4+10;
     5 struct G{
     6     int t,x;
     7     friend bool operator <(const G &a,const G &b){
     8         return a.t<b.t;
     9     }
    10 }g[M];
    11 int main(){
    12     int t,n;
    13     while(~scanf("%d",&t)){
    14         int cas=1;
    15         while(t--){
    16             scanf("%d",&n);
    17             for(int i=0;i<n;i++){
    18                 scanf("%d%d",&g[i].t,&g[i].x);
    19             }
    20             sort(g,g+n);
    21             double ans=0;
    22             for(int i=0;i<n-1;i++){
    23                 ans=max(ans,abs(g[i].x-g[i+1].x)*1.0/(g[i+1].t-g[i].t));
    24             }
    25             printf("Case #%d: %.2f
    ",cas++,ans);
    26         }
    27     }
    28     return 0;
    29 }
    View Code

    D http://acm.hdu.edu.cn/showproblem.php?pid=5115

    有n只狼排成一排,每一步消灭一只,每次消灭花费当前这只狼的a,以及左右两边最近的两只的b,ai+bleft+bright。问消灭所有狼最小花费。

    解法:若暴力,可以n!,算花费取最小值。优化一点状态压缩,可以从二进制111-》000,最后dp【0】的最小值就是答案。复杂度2^n.再优化

    定义dp【i】【j】表示消灭i到j最小花费。答案就是dp【1】【n】。转移时枚举i到j中最后一个被杀的,假设是k,那么转移就是

    dp【i】【j】=min(dp【i】【j】,dp【i】【k-1】+dp【k+1】【j】+a【k】+b【i-1】+b【j+1】);

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=256;
     5 const int inf=0x3f3f3f3f;
     6 int a[M],b[M],dp[M][M];
     7 int main(){
     8     int t,n;
     9     while(~scanf("%d",&t)){
    10         int cas=1;
    11         while(t--){
    12             scanf("%d",&n);
    13             for(int i=1;i<=n;i++){
    14                 scanf("%d",&a[i]);
    15             }
    16             for(int i=1;i<=n;i++){
    17                 scanf("%d",&b[i]);
    18             }
    19             b[0]=b[n+1]=0;
    20             for(int i=1;i<=n;i++){
    21                 for(int j=i;j<=n;j++){
    22                     dp[i][j]=inf;
    23                 }
    24             }
    25             for(int len=1;len<=n;len++){
    26                 for(int i=1;i+len-1<=n;i++){
    27                     for(int j=i;j<i+len;j++){
    28                         int cost=a[j]+b[i-1]+b[i+len];
    29                         if(j>i){
    30                             cost+=dp[i][j-1];
    31                         }
    32                         if(j<i+len-1){
    33                             cost+=dp[j+1][i+len-1];
    34                         }
    35                         dp[i][i+len-1]=min(dp[i][i+len-1],cost);
    36                     }
    37                 }
    38             }
    39             printf("Case #%d: %d
    ",cas++,dp[1][n]);
    40         }
    41     }
    42     return 0;
    43 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=5119

    有40个数,问选一个子集异或之和大于等于m的有多少种选法。

    解法:朴素算法,暴力所有子集验证答案,2^40的时间复杂度,01背包

    定义dp【i】【j】表示前n个异或和为j的情况数,则答案为dp【n】【j】,j>=m。

    转移就两个 ,选或者不选。

     1 #include<cstdio>
     2 typedef long long LL;
     3 const int M=50;
     4 int a[M];
     5 LL dp[M][1<<20];
     6 int main(){
     7     int t,n,m;
     8     while(~scanf("%d",&t)){
     9         int cas=1;
    10         while(t--){
    11             scanf("%d%d",&n,&m);
    12             for(int i=1;i<=n;i++){
    13                 scanf("%d",&a[i]);
    14             }
    15             int big=1<<20;
    16             for(int i=0;i<=n;i++){
    17                 for(int j=0;j<big;j++){
    18                     dp[i][j]=0;
    19                 }
    20             }
    21             dp[0][0]=1;
    22             for(int i=0;i<=n;i++){
    23                 for(int j=0;j<big;j++){
    24                     if(!dp[i][j]) continue;
    25                     dp[i+1][j^a[i+1]]+=dp[i][j];
    26                     dp[i+1][j]+=dp[i][j];
    27                 }
    28             }
    29             LL ans=0;
    30             for(int j=m;j<big;j++){
    31                 ans+=dp[n][j];
    32             }
    33             printf("Case #%d: %I64d
    ",cas++,ans);
    34         }
    35     }
    36     return 0;
    37 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=5120

    问两个圆环交的面积。

    解法:容斥原理?算两个大圆面积交,扣掉左边大圆与右边小圆的交,再扣掉左边小圆与右边大圆的交,再把两个小圆的交加回来。

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<algorithm>
     4 using namespace std;
     5 const double eps=1e-8;
     6 const double pi=acos(-1.0);
     7 struct point {
     8     double x,y;
     9 } c1,c2;
    10 double Distance(point p1,point p2) {
    11     return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
    12 }
    13 point intersection(point u1,point u2,point v1,point v2) {
    14     point ret=u1;
    15     double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x)) /((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
    16     ret.x+=(u2.x-u1.x)*t;
    17     ret.y+=(u2.y-u1.y)*t;
    18     return ret;
    19 }
    20 void intersection_line_circle(point c,double r,point l1,point l2,point& p1,point& p2) {
    21     point p=c;
    22     double t;
    23     p.x+=l1.y-l2.y;
    24     p.y+=l2.x-l1.x;
    25     p=intersection(p,c,l1,l2);
    26     t=sqrt(r*r-Distance(p,c)*Distance(p,c))/Distance(l1,l2);
    27     p1.x=p.x+(l2.x-l1.x)*t;
    28     p1.y=p.y+(l2.y-l1.y)*t;
    29     p2.x=p.x-(l2.x-l1.x)*t;
    30     p2.y=p.y-(l2.y-l1.y)*t;
    31 }
    32 void intersection_circle_circle(point c1,double r1,point c2,double r2,point& p1,point& p2) {
    33     point u,v;
    34     double t;
    35     t=(1+(r1*r1-r2*r2)/Distance(c1,c2)/Distance(c1,c2))/2;
    36     u.x=c1.x+(c2.x-c1.x)*t;
    37     u.y=c1.y+(c2.y-c1.y)*t;
    38     v.x=u.x+c1.y-c2.y;
    39     v.y=u.y-c1.x+c2.x;
    40     intersection_line_circle(c1,r1,u,v,p1,p2);
    41 }
    42 double xmult(point p1,point p2,point p0) {
    43     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
    44 }
    45 double area_triangle(point p1,point p2,point p3) {
    46     return fabs(xmult(p1,p2,p3))/2;
    47 }
    48 int same_side(point p1,point p2,point l1,point l2) {
    49     return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;
    50 }
    51 double area_circle_circle(point a,double r1,point b,double r2) {
    52     if(r1<eps||r2<eps)return 0.0;
    53     double temp=Distance(a,b);
    54     point p1,p2;
    55     double co1,co2,ret=0.0,du1,du2,z;
    56     if(temp+eps>=r1+r2) {
    57         return 0.0;
    58     } else if(temp-eps<=fabs(r1-r2)) {
    59         temp=min(r1,r2);
    60         return pi*temp*temp;
    61     } else {
    62         intersection_circle_circle(a,r1,b,r2,p1,p2);
    63         temp=Distance(p1,p2);
    64         co1=(r1*r1*2.0-temp*temp)/(2.0*r1*r1);
    65         du1=acos(co1);
    66         z=(r1*r1*du1/2.0-area_triangle(p1,p2,a));
    67         if(same_side(a,b,p1,p2)&&r1<r2)z=pi*r1*r1-z;
    68         ret+=z;
    69         co2=(r2*r2*2.0-temp*temp)/(2.0*r2*r2);
    70         du2=acos(co2);
    71         z=(r2*r2*du2/2.0-area_triangle(p1,p2,b));
    72         if(same_side(a,b,p1,p2)&&r2<r1)z=pi*r2*r2-z;
    73         ret+=z;
    74         return ret;
    75     }
    76 }
    77 int main() {
    78     int t;
    79     double r,R;
    80     while(~scanf("%d",&t)) {
    81         int cas=1;
    82         while(t--) {
    83             scanf("%lf%lf%lf%lf%lf%lf",&r,&R,&c1.x,&c1.y,&c2.x,&c2.y);
    84             printf("Case #%d: %.6f
    ",cas++,area_circle_circle(c1,R,c2,R)-area_circle_circle(c1,r,c2,R)-area_circle_circle(c1,R,c2,r)+area_circle_circle(c1,r,c2,r));
    85         }
    86     }
    87     return 0;
    88 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=5122

    输入n的一个排列,问最少多少次操作能将其从小到大排好序, 每次操作可以任意选一个数,不断的往后交换直至后一个大于他停止。

    解法:首先选必须要从大往小选,这样最多n次就能排好序,就是逆序的情况。因为如果选个中间的,他往后换的过程可能会遇到一个较大的使得他停下,没达到需要到的位置,从大到小选就避免了这种情况,是最优的方法。问题转化为如何统计步数。我们定义一个需求need,表示当前需要选的数,定义一个指针p,表示当前位置,指针从最后一个位置开始,需求从n开始。每次迭代,若指针的位置的值a【p】恰好等于need,则我们不需要浪费步数,数就在他应该在的位置。若a【p】小于need,说明这个位置应该放的是need,我们需要消耗一步,将前面的need移动至此,但我们不需改动数组的值,因为改动的复杂度是on的。此时我们只需要记录ans++,need--,p不动。若a【p】大于need,说明这个值已经处理过了,p--。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=1e6+10;
     5 int a[M];
     6 int main(){
     7     int t,n;
     8     while(~scanf("%d",&t)){
     9         int cas=1;
    10         while(t--){
    11             scanf("%d",&n);
    12             for(int i=0;i<n;i++){
    13                 scanf("%d",&a[i]);
    14             }
    15             int ans=0;
    16             int p=n-1;
    17             for(int i=n;i>=1;i--){
    18                 if(a[p]==i){
    19                     p--;
    20                     continue;
    21                 }
    22                 if(a[p]>i){
    23                     p--;
    24                     i++;
    25                     continue;
    26                 }
    27                 ans++;
    28             }
    29             printf("Case #%d: %d
    ",cas++,ans);
    30         }
    31     }
    32     return 0;
    33 }
    View Code

    end

  • 相关阅读:
    大型运输行业实战_day03_1_基于intellij idea的非maven spring+springMVC+mybatis搭建
    大型运输行业实战_day02_2_数据模型建立
    大型运输行业实战_day02_1_数据库设计与powerDesigner使用
    MySQL 并发控制(锁得使用)
    Oracle 日期减年数、两日期相减
    Oracle 递归拼接字段
    设计模式之适配器模式(结构型)
    设计模式之桥接模式(结构型)
    设计模式之装饰模式(结构型)
    Redis学习笔记之位图
  • 原文地址:https://www.cnblogs.com/gaolzzxin/p/4667876.html
Copyright © 2011-2022 走看看