zoukankan      html  css  js  c++  java
  • 第六周周赛题解

    A题

    这题贼水,直接暴力就可以了。

    用个bool数组记录一下,如果某一天,当前剩下的最大的出现了的话,就输出一段。

     1 #include<stdio.h>
     2 int n;
     3 bool vis[100010];
     4 int main()
     5 {
     6     scanf("%d",&n);
     7     int x;
     8     int now=n;
     9     for(int i=1;i<=n;++i)
    10       {
    11           scanf("%d",&x);
    12           vis[x]=1;
    13           if(vis[now])
    14             {
    15                 printf("%d",now);
    16                 --now;
    17                 while(vis[now])
    18                   {
    19                     printf(" %d",now);
    20                     --now;
    21                   }
    22             }
    23           printf("
    ");
    24       }
    25     return 0;
    26 }
    View Code

    B题

    又是水题,你们肯定要感谢我

    只要求每个数对最大的数的绝对值的和就可以了

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 int n, ai;
     5 int main()
     6 {
     7     scanf("%d", &n);
     8     int maxi = 0;
     9     int sum = 0;
    10     for (int i = 0; i < n; i++)
    11     {
    12         scanf("%d", &ai);
    13         sum += ai;
    14         maxi = max(maxi, ai);
    15     }
    16     int res = maxi * n - sum;
    17     printf("%d", res);
    18     return 0;
    19 }
    View Code

    C题

    这一题开始就有点难了,DFS+回溯

    题目大意: 任选一个起点,按照国际象棋马的跳法,不重复的跳完整个棋盘,如果有多种路线则选择字典序最小的路线(路线是点的横纵坐标的集合,注意棋盘的横坐标的用大写字母,纵坐标是数字)

    1. 应该看到这个题就可以想到用DFS,当首先要明白这个题的意思是能否只走一遍(不回头不重复)将整个地图走完,而普通的深度优先搜索是一直走,走不通之后沿路返回到某处继续深搜。所以这个题要用到的回溯思想,如果不重复走一遍就走完了,做一个标记,算法停止;否则在某种DFS下走到某一步时按马跳的规则无路可走而棋盘还有为走到的点,这样我们就需要撤消这一步,进而尝试其他的路线(当然其他的路线也可能导致撤销),而所谓撤销这一步就是在递归深搜返回时重置该点,以便在当前路线走一遍行不通换另一种路线时,该点的状态是未访问过的,而不是像普通的DFS当作已经访问了。

    2. 如果有多种方式可以不重复走一遍的走完,需要输出按字典序最小的路径,而注意到国际象棋的棋盘是列为字母,行为数字,如果能够不回头走一遍的走完,一定会经过A1点,所以我们应该从A1开始搜索,以确保之后得到的路径字典序是最小的(也就是说如果路径不以A1开始,该路径一定不是字典序最小路径),而且我们应该确保优先选择的方向是字典序最小的方向,这样我们最先得到的路径就是字典序最小的。

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include<string.h>
     4 using namespace std;
     5 
     6 const int MAX_N = 27;
     7 
     8 const int dx[8] = {-1, 1, -2, 2, -2, 2, -1, 1};
     9 const int dy[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
    10 bool visited[MAX_N][MAX_N];
    11 struct Step{
    12     char x, y;
    13 } path[MAX_N];
    14 bool success;           //是否成功遍历的标记
    15 int cases, p, q;
    16 
    17 void DFS(int x, int y, int num);
    18 
    19 int main()
    20 {
    21     scanf("%d", &cases);
    22     for (int c = 1; c <= cases; c++)
    23     {
    24         success = false;
    25         scanf("%d%d", &p, &q);
    26         memset(visited, false, sizeof(visited));
    27         visited[1][1] = true;    //起点
    28         DFS(1, 1, 1);
    29         printf("Scenario #%d:
    ", c);
    30         if (success)
    31         {
    32             for (int i = 1; i <= p * q; i++)
    33                 printf("%c%c", path[i].y, path[i].x);
    34             printf("
    ");
    35         }
    36         else
    37             printf("impossible
    ");
    38         if (c != cases)
    39             printf("
    ");      //注意该题的换行
    40     }
    41     return 0;
    42 }
    43 
    44 void DFS(int x, int y, int num)
    45 {
    46     path[num].y = y + 'A' - 1;   //int 转为 char
    47     path[num].x = x + '0';
    48     if (num == p * q)
    49     {
    50         success = true;
    51         return;
    52     }
    53     for (int i = 0; i < 8; i++)
    54     {
    55         int nx = x + dx[i];
    56         int ny = y + dy[i];
    57         if (0 < nx && nx <= p && 0 < ny && ny <= q
    58             && !visited[nx][ny] && !success)
    59         {
    60             visited[nx][ny] = true;
    61             DFS(nx, ny, num+1);
    62             visited[nx][ny] = false;    //撤销该步
    63         }
    64     }
    65 }
    View Code

    D题

    这题是我原创的题目233,其实是一道有关分治的裸题,其实就是最接近点对问题

    给定平面S上n个点,找其中的一对点,使得在n(n-1)/2 个点对中,该点对的距离最小。

    算法思路就是

     1) n较小时直接求 (n=2).                                                         
     2) 将S上的n个点分成大致相等的2个子集S1和S2    
     3) 分别求S1和S2中的最接近点对
    4) 求一点在S1、另一点在S2中的最近点对
     5) 从上述三对点中找距离最近的一对.

    仔细分析上面的过程,只有第4步有些困难,其它几个步骤只要递归下去就行了。看下面这个图,我们把点分成了左右两部分S1和S2,并且分别求得了最小距离为dl,dr。 令 d = min(dl,dr):

    divide_points_new1

    接下来要考虑的就是 两个端点分别在左右两部分中的点对。已经知道最小距离不会超过d。我们在拆分两部分的时候把 P [N/2] 作为中间点。做一条过P的垂直线,并找到所有距离垂直线距离在d以内的点,把这些点放在数组strip[] 中,如下图所示。其它点就可以不用考虑了。

    strip_closesr1

    接下来计算strip[]中的最小距离点对。按照y坐标排序,这一步需要O(nLogn)的复杂度,其实可以 通过递归和归并优化到O(n)。由于已经排序,我们可以再O(n)内找到最小距离点对d3(这里其实需要一些几何知识来证明,参考:http://people.csail.mit.edu/indyk/6.838-old/handouts/lec17.pdf)。

    贴上学长T^T的代码

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 using namespace std;
     7 const double INF = 1e20;
     8 const int N = 100005;
     9 
    10 struct Point
    11 {
    12     double x;
    13     double y;
    14 }point[N];
    15 int n;
    16 int tmpt[N];
    17 
    18 bool cmpxy(const Point& a, const Point& b)
    19 {
    20     if(a.x != b.x)
    21         return a.x < b.x;
    22     return a.y < b.y;
    23 }
    24 
    25 bool cmpy(const int& a, const int& b)
    26 {
    27     return point[a].y < point[b].y;
    28 }
    29 
    30 double min(double a, double b)
    31 {
    32     return a < b ? a : b;
    33 }
    34 
    35 double dis(int i, int j)
    36 {
    37     return sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)
    38                 + (point[i].y-point[j].y)*(point[i].y-point[j].y));
    39 }
    40 
    41 double Closest_Pair(int left, int right)
    42 {
    43     double d = INF;
    44     if(left==right)
    45         return d;
    46     if(left + 1 == right)
    47         return dis(left, right);
    48     int mid = (left+right)>>1;
    49     double d1 = Closest_Pair(left,mid);
    50     double d2 = Closest_Pair(mid+1,right);
    51     d = min(d1,d2);
    52     int i,j,k=0;
    53     //分离出宽度为d的区间
    54     for(i = left; i <= right; i++)
    55     {
    56         if(fabs(point[mid].x-point[i].x) <= d)
    57             tmpt[k++] = i;
    58     }
    59     sort(tmpt,tmpt+k,cmpy);
    60     //线性扫描
    61     for(i = 0; i < k; i++)
    62     {
    63         for(j = i+1; j < k && point[tmpt[j]].y-point[tmpt[i]].y<d; j++)
    64         {
    65             double d3 = dis(tmpt[i],tmpt[j]);
    66             if(d > d3)
    67                 d = d3;
    68         }
    69     }
    70     return d;
    71 }
    72 
    73 
    74 int main()
    75 {
    76     while(~scanf("%d",&n))
    77     {   for(int i = 0; i < n; i++)
    78             scanf("%lf %lf",&point[i].x,&point[i].y);
    79         sort(point,point+n,cmpxy);
    80         printf("%lf
    ",Closest_Pair(0,n-1));
    81     }
    82     return 0;
    83 }
    View Code

    E题

    这题几何题233。

    解法如下:不需要正规的三角剖分,用求多边形面积的思想,从一点出发连接多边形的边得到很多三
    角形,三角形有向边方向决定有向面积有正有负,相加得到多边形面积的正值或负值。
    把两个多边形都分成若干这样的三角形,求每对三角形的交,根据两三角形有向边顺逆时
    针关系确定相交面积的正负号,最后两多边形面积和减去相交面积。

      1 #include<stdio.h>
      2  #include<string.h>
      3  #include<stdlib.h>
      4  #include<math.h>
      5  #include<algorithm>
      6  const int maxn = 555;
      7  const int maxisn = 10;
      8  const double eps = 1e-8;
      9  const double pi = acos(-1.0);
     10  int dcmp(double x)
     11  {
     12      if(x > eps) return 1;
     13      return x < -eps ? -1 : 0;
     14  }
     15  inline double min(double a, double b)
     16  {return a < b ? a : b;}
     17  inline double max(double a, double b)
     18  {return a > b ? a : b;}
     19  inline double Sqr(double x)
     20  {return x * x;}
     21  struct Point
     22  {
     23      double x, y;
     24      Point(){x = y = 0;}
     25      Point(double a, double b)
     26      {x = a, y = b;}
     27      inline Point operator-(const Point &b)const
     28      {return Point(x - b.x, y - b.y);}
     29      inline Point operator+(const Point &b)const
     30      {return Point(x + b.x, y + b.y);}
     31      inline double dot(const Point &b)const
     32      {return x * b.x + y * b.y;}
     33      inline double cross(const Point &b, const Point &c)const
     34      {return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);}
     35  };
     36  Point LineCross(const Point &a, const Point &b, const Point &c, const Point &d)
     37  {
     38      double u = a.cross(b, c), v = b.cross(a, d);
     39      return Point((c.x * v + d.x * u) / (u + v), (c.y * v + d.y * u) / (u + v));
     40  }
     41  double PolygonArea(Point p[], int n)
     42  {
     43      if(n < 3) return 0.0;
     44      double s = p[0].y * (p[n - 1].x - p[1].x);
     45      p[n] = p[0];
     46      for(int i = 1; i < n; ++ i)
     47          s += p[i].y * (p[i - 1].x - p[i + 1].x);
     48      return fabs(s * 0.5);
     49  }
     50  double CPIA(Point a[], Point b[], int na, int nb)//ConvexPolygonIntersectArea
     51  {
     52      Point p[maxisn], tmp[maxisn];
     53      int i, j, tn, sflag, eflag;
     54      a[na] = a[0], b[nb] = b[0];
     55      memcpy(p, b, sizeof(Point) * (nb + 1));
     56      for(i = 0; i < na && nb > 2; ++ i)
     57      {
     58          sflag = dcmp(a[i].cross(a[i + 1], p[0]));
     59          for(j = tn = 0; j < nb; ++ j, sflag = eflag)
     60          {
     61              if(sflag >= 0) tmp[tn ++] = p[j];
     62              eflag = dcmp(a[i].cross(a[i + 1], p[j + 1]));
     63              if((sflag ^ eflag) == -2)
     64                  tmp[tn ++] = LineCross(a[i], a[i + 1], p[j], p[j + 1]);
     65          }
     66          memcpy(p, tmp, sizeof(Point) * tn);
     67          nb = tn, p[nb] = p[0];
     68      }
     69      if(nb < 3) return 0.0;
     70      return PolygonArea(p, nb);
     71  }
     72  double SPIA(Point a[], Point b[], int na, int nb)//SimplePolygonIntersectArea
     73  {
     74      int i, j;
     75      Point t1[4], t2[4];
     76      double res = 0, if_clock_t1, if_clock_t2;
     77      a[na] = t1[0] = a[0], b[nb] = t2[0] = b[0];
     78      for(i = 2; i < na; ++ i)
     79      {
     80          t1[1] = a[i - 1], t1[2] = a[i];
     81          if_clock_t1 = dcmp(t1[0].cross(t1[1], t1[2]));
     82          if(if_clock_t1 < 0) std::swap(t1[1], t1[2]);
     83          for(j = 2; j < nb; ++ j)
     84          {
     85              t2[1] = b[j - 1], t2[2] = b[j];
     86              if_clock_t2 = dcmp(t2[0].cross(t2[1], t2[2]));
     87              if(if_clock_t2 < 0) std::swap(t2[1], t2[2]);
     88              res += CPIA(t1, t2, 3, 3) * if_clock_t1 * if_clock_t2;
     89          }
     90      }
     91      return PolygonArea(a, na) + PolygonArea(b, nb) - res;
     92  }
     93  Point p1[maxn], p2[maxn];
     94  int n1, n2;
     95  int main()
     96  {
     97      int i;
     98      while(scanf("%d%d", &n1, &n2) != EOF)
     99      {
    100          for(i = 0; i < n1; ++ i) scanf("%lf%lf", &p1[i].x, &p1[i].y);
    101          for(i = 0; i < n2; ++ i) scanf("%lf%lf", &p2[i].x, &p2[i].y);
    102          printf("%.2f
    ", SPIA(p1, p2, n1, n2) + eps);
    103      }
    104      return 0;
    105  }
    View Code

    F题

    这题怎么说呢,题意就是:给一系列操作,每个操作有两个数t和k,t=0表示求k以内的最大反素数;t=1表示求小于k且与k互质的数的个数。

    大概就是对第一个操作,直接用dfs求反素数就行了;

    第二个操作素数筛法的思想预先打个表。

     1 #include<stdio.h>
     2 #include<algorithm>
     3 const long long INF = (((long long)1)<<62)+1;
     4 using namespace std;
     5 const int MAXN = 300 + 10;
     6 const double M=1e-8;
     7 const int N=50100;
     8 const int d[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
     9 int n,m,st[N],lazy[N],a[N];
    10 int p[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
    11 long long ans,ip[N];
    12 void init()
    13 {
    14     int i,j;
    15     for(i=1;i<N;i++) ip[i]=i;           //初始化i最多有i个与其互质的数
    16     for(i=1;i<N;i++)
    17     {
    18           for(j=i;j<=N;j+=i) ip[j]--;    //i为j的因子,所以j与i不互质,第j个数的互质数减少1
    19           if(!ip[ip[i]]) ip[ip[i]]=i;     //此时ip[i]存的是不大于i的数与i互质的个数k=ip[i],
    20            //如果ip[k]=0,表示小于i的所有数中,没有刚好有k个互质数的数
    21            //故将ip[k]=i,表示刚好有k个与i互质的数个数最小为i
    22           ip[i]=0; //标记刚好有k个互质数的数没有(不大于i的数不可能存在某个数与其互质的数的个数等于i);
    23     }
    24 }
    25 void dfs(int k,long long num,long long sum,int limit)
    26 {
    27     if (sum>n) return ;
    28     if (sum==n) ans=min(ans,num);
    29     for (int i=1;i<=limit;i++) {
    30         if (ans/p[k] <num || sum*(i+1)>n) break;
    31         num*=p[k];
    32         if (n%(sum*(i+1))==0)
    33             dfs(k+1,num,sum*(i+1),i);
    34     }
    35 }
    36 int main()
    37 {
    38     int i,j,cnt=1;
    39     int t;
    40     init();
    41     scanf("%d",&t);
    42     while(t--)
    43     {
    44         int t;
    45         scanf("%d%d",&t,&n);
    46         if (t) {
    47             ans=ip[n];
    48         }
    49         else {
    50             ans=INF;
    51             dfs(0,1,1,62);
    52         }
    53         printf("Case %d: ",cnt++);
    54         if (ans==0) puts("Illegal");
    55         else if (ans>=INF) puts("INF");
    56         else printf("%lld
    ",ans);
    57     }
    58 }
    View Code
  • 相关阅读:
    自我介绍
    秋季学期总结
    第七周编程总结
    第六周作业
    第五周编程总结
    第四周编程总结
    第三周作业
    第二周作业
    抓老鼠啊~亏了还是赚了
    币值转换
  • 原文地址:https://www.cnblogs.com/tijie/p/6613480.html
Copyright © 2011-2022 走看看