zoukankan      html  css  js  c++  java
  • TZOJ 挑战题库随机训练08(JAVA)

    点击题号跳转

    A2441 B2293 C1724 D3462 E1608

    F5065 G2427 H5466 I5603 J3299

    A.Work Reduction回到顶部

    题意

    n变成m,两种操作,减1花费A,整除2花费B,问最小花费

    题解

    n变成n/2,操作1需要花费(n-n/2)*A,操作2需要花费B,比大小决定,复杂度O(logn)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         Solution solver = new Solution();
     9         int t = sc.nextInt();
    10         for (int ca = 1; ca <= t; ca++) {
    11             System.out.println("Case " + ca);
    12             solver.solve(sc);
    13         }
    14     }
    15 
    16 }
    17 
    18 class Solution {
    19 
    20     class Node {
    21         String name;
    22         int sumCost;
    23 
    24         Node(String name, int sumCost) {
    25             this.name = name;
    26             this.sumCost = sumCost;
    27         }
    28     }
    29 
    30     public void solve(Scanner sc) {
    31         int n = sc.nextInt();
    32         int m = sc.nextInt();
    33         int agencies = sc.nextInt();
    34         sc.nextLine();// 读回车
    35         List<Node> list = new ArrayList<Node>();
    36         for (int i = 0; i < agencies; i++) {
    37             String s = sc.nextLine();
    38             String[] str = s.split(":");
    39             String[] str1 = str[1].split(",");
    40             int aCost = Integer.valueOf(str1[0]);
    41             int bCost = Integer.valueOf(str1[1]);
    42             int val = n;
    43             int sumCost = 0;
    44             while (val > m) {
    45                 int updateTo = val / 2;
    46                 int aSumCost = aCost * (val - updateTo);
    47                 if (updateTo >= m && aSumCost > bCost) {
    48                     sumCost += bCost;
    49                     val = updateTo;
    50                 } else {
    51                     // 剩下一段全A
    52                     sumCost += (val - m) * aCost;
    53                     break;
    54                 }
    55             }
    56             list.add(new Node(str[0], sumCost));
    57         }
    58 
    59         Collections.sort(list, new Comparator<Node>() {
    60             public int compare(Node o1, Node o2) {
    61                 if (o1.sumCost > o2.sumCost)
    62                     return 1;
    63                 else if (o1.sumCost == o2.sumCost) {
    64                     if (o1.name.compareTo(o2.name) > 0)
    65                         return 1;
    66                     else
    67                         return -1;
    68                 }
    69                 else return -1;
    70             }
    71         });
    72 
    73         for (int i = 0; i < list.size(); i++)
    74             System.out.println(list.get(i).name + " " + list.get(i).sumCost);
    75     }
    76 
    77 }
    A

    B.Collecting Beepers回到顶部

    题意

    10个点,给个起点,问经过每个点再回到起点的最小距离

    题解

    爆搜,最后加上到起点的距离,复杂度O(2^10)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         Solution solver = new Solution();
     9         int t = sc.nextInt();
    10         for (int ca = 1; ca <= t; ca++) {
    11             solver.solve(sc);
    12         }
    13     }
    14 
    15 }
    16 
    17 class Solution {
    18 
    19     private int[] x;
    20     private int[] y;
    21     private boolean[] vis;
    22     private int q;
    23     private int sx, sy;
    24     private int min;
    25 
    26     public void solve(Scanner sc) {
    27         int n = sc.nextInt();
    28         int m = sc.nextInt();
    29         sx = sc.nextInt();
    30         sy = sc.nextInt();
    31         q = sc.nextInt();
    32         x = new int[q];
    33         y = new int[q];
    34         vis = new boolean[q];
    35         min = 1000000000;
    36         for (int i = 0; i < q; i++) {
    37             x[i] = sc.nextInt();
    38             y[i] = sc.nextInt();
    39         }
    40         dfs(0, 0, sx, sy);
    41         System.out.println("The shortest path has length " + min);
    42     }
    43 
    44     private void dfs(int step, int cost, int ux, int uy) {
    45         if (step == q) {
    46             min = Math.min(min, cost + Math.abs(ux - sx) + Math.abs(uy - sy));
    47             return;
    48         }
    49         if (cost <= min) {
    50             for (int i = 0; i < q; i++) {
    51                 if (!vis[i]) {
    52                     vis[i] = true;
    53                     dfs(step + 1, cost + Math.abs(x[i] - ux) + Math.abs(y[i] - uy), x[i], y[i]);
    54                     vis[i] = false;
    55                 }
    56             }
    57         }
    58     }
    59 }
    B

    C.Guess how much I love you?回到顶部

    题意

    n个串,按TOJ和JOT的个数大到小排序,若个数相同按长度大到小排序,若长度相同按字典序小到大排序,串总长<=10000

    题解

    处理出每个串的TOJ和JOT的个数,调用Collections.sort方法排序,匿名内部类new Comparator,然后排序需要把@Override去掉,复杂度O(10000)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         Solution solver = new Solution();
     9         int t = sc.nextInt();
    10         for (int ca = 1; ca <= t; ca++) {
    11             solver.solve(sc);
    12         }
    13     }
    14 
    15 }
    16 
    17 class Solution {
    18     class Node {
    19         String s;
    20         int num;
    21         Node() {
    22             num = 0;
    23         }
    24     }
    25     public void solve(Scanner sc) {
    26         int n = sc.nextInt();
    27         sc.nextLine(); // 读回车
    28         List<Node> list = new ArrayList<Node>();
    29         for (int i = 0; i < n; i++) {
    30             Node node = new Node();
    31             node.s = sc.nextLine();
    32             for (int j = 2; j < node.s.length(); j++) {
    33                 if ("TOJ".equals(node.s.substring(j - 2, j + 1)) || "JOT".equals(node.s.substring(j - 2, j + 1))) {
    34                     node.num++;
    35                 }
    36             }
    37             list.add(node);
    38         }
    39         Collections.sort(list, new Comparator<Node>() {
    40             public int compare(Node o1, Node o2) {
    41                 // 正数交换 其余不换
    42                 if (o1.num < o2.num) {
    43                     return 1;
    44                 } else if (o1.num > o2.num){
    45                     return -1;
    46                 } else {
    47                     if (o1.s.length() < o2.s.length())
    48                         return 1;
    49                     else if (o1.s.length() == o2.s.length())
    50                         if (o1.s.compareTo(o2.s) < 0)
    51                             return 1;
    52                         else
    53                             return -1;
    54                     else {
    55                         return -1;
    56                     }
    57                 }
    58             }
    59         });
    60         for (int i = 0; i < list.size(); i++) {
    61             System.out.println(list.get(i).s);
    62         }
    63     }
    64 }
    C

    D.F**king string!回到顶部

    题意

    n(<=10)个串长度最大100,再给一个错误串,n个串都取前k个字符和错误串的最长公共子串>=d,求最小的k,若不存在-1

    题解

    易得k的范围[d,n个串+错误串的最小长度],枚举n个串

    对于一个串,存在一个k,使得满足最长公共子串>=d,那么k+1也满足(优化)

    可以用dp求出最长公共子串长度即可,复杂度O(100^3)

    PS:一开始以为错误串也要去前k个,幸好反应过来了

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     private Scanner sc;
     6     public static void main(String[] args) {
     7 
     8         Scanner sc = new Scanner(System.in);
     9         Solution solver = new Solution();
    10         while (solver.solve(sc) != -1) {
    11 
    12         }
    13     }
    14 
    15 }
    16 
    17 class Solution {
    18 
    19     String[] str;
    20     public int solve(Scanner sc) {
    21         int n = sc.nextInt();
    22         int d = sc.nextInt();
    23         if (n == 0 && d == 0) return -1;
    24         str = new String[n + 5];
    25         int upLength = 1000000000;
    26         for (int i = 0; i < n; i++) {
    27             str[i] = sc.next();
    28             upLength = Math.min(upLength, str[i].length());
    29         }
    30         str[n] = sc.next();
    31         upLength = Math.min(upLength, str[n].length());
    32         boolean[] vis = new boolean[n];
    33         for (int i = 0; i < n; i++) vis[i] = false;
    34         int k = -1;
    35         for (int len = d; len <= upLength; len++) {
    36             boolean ok = true;
    37             for (int i = 0; i < n; i++) {
    38                 // 如果之前的len就合法,不用判断了
    39                 if (vis[i]) continue;
    40                 // str[n]和str[i]的[0,len)最长公共子串
    41                 int common = LCS(str[n], str[i].substring(0, len));
    42                 if (common < d) {
    43                     ok = false;
    44                     break;
    45                 } else {
    46                     vis[i] = true;
    47                 }
    48             }
    49             if (ok) {
    50                 k = len;
    51                 break;
    52             }
    53         }
    54         System.out.println(k);
    55         return 1;
    56     }
    57 
    58     private int LCS(String s1, String s2) {
    59         int[][] dp = new int[s1.length()][s2.length()];
    60         int maxLength = 0;
    61         for (int i = 0; i < s1.length(); i++)
    62             for (int j = 0; j < s2.length(); j++) {
    63                 if (s1.charAt(i) == s2.charAt(j))
    64                     if (i > 0 && j > 0) dp[i][j] = dp[i - 1][j - 1] + 1;
    65                     else dp[i][j] = 1;
    66                 else
    67                     dp[i][j] = 0;
    68                 maxLength = Math.max(maxLength, dp[i][j]);
    69             }
    70         return maxLength;
    71     }
    72 }
    D

    E.Distance Statistics回到顶部

    题意

    给一张图n,m<=10^5,求点对距离<=k的数量

    题解

    点分治模板题

    点分治用在去掉某个点后,这个点不影响对答案的贡献

    算法流程大概是,求出树的重心,求出重心到每个点的距离,双指针计算方案,容斥掉两点同向的情况,再移除重心,同理计算剩下的子树

    复杂度O(nlog^2n)

    PS:服务器jdk版本改成1.8,java代码已经可以过了

    代码

      1 import java.util.*;
      2 
      3 public class Main {
      4 
      5     private Scanner sc;
      6 
      7     public static void main(String[] args) {
      8 
      9         Scanner sc = new Scanner(System.in);
     10         Solution solver = new Solution();
     11         solver.solve(sc);
     12     }
     13 
     14 }
     15 
     16 class Solution {
     17 
     18     private final int N = 100005;
     19 
     20     private int n, m, k;
     21     private int MIN, ans, root;
     22     private int[] mx = new int[N];
     23     private int[] sz = new int[N];
     24     private boolean[] vis = new boolean[N];
     25     private List<Integer> dis = new ArrayList<Integer>();
     26     private List< ArrayList<Node> > G = new ArrayList< ArrayList<Node> >();
     27 
     28     class Node {
     29         int v, w;
     30 
     31         Node(int v, int w) {
     32             this.v = v;
     33             this.w = w;
     34         }
     35     }
     36 
     37     private void init() {
     38         for (int i = 0; i < N; i++) {
     39             G.add(new ArrayList<Node>());
     40             vis[i] = false;
     41         }
     42     }
     43 
     44     public void solve(Scanner sc) {
     45         n = sc.nextInt();
     46         m = sc.nextInt();
     47         init();
     48         for (int i = 0; i < m; i++) {
     49             int u = sc.nextInt() - 1;
     50             int v = sc.nextInt() - 1;
     51             int w = sc.nextInt();
     52             sc.next();
     53             G.get(u).add(new Node(v, w));
     54             G.get(v).add(new Node(u, w));
     55         }
     56         k = sc.nextInt();
     57         dfs(0);
     58         System.out.println(ans);
     59     }
     60 
     61     private void dfs(int u) {
     62         MIN = n;
     63         dfsSz(u, u);
     64         dfsRoot(u, u, u);
     65         int gri = root;
     66         //System.out.println("grivate:" + gri);
     67         ans += cal(gri, 0);
     68         //System.out.println("u:" + u);
     69         //System.out.println("ans:" + ans);
     70         vis[root] = true;
     71         for (int i = 0; i < G.get(gri).size(); i++) {
     72             int v = G.get(gri).get(i).v;
     73             int w = G.get(gri).get(i).w;
     74             if (!vis[v]) {
     75                 ans -= cal(v, w);
     76                 dfs(v);
     77             }
     78         }
     79     }
     80 
     81     private void dfsSz(int u, int fa) {
     82         sz[u] = 1;
     83         mx[u] = 0;
     84         for (int i = 0; i < G.get(u).size(); i++) {
     85             int v = G.get(u).get(i).v;
     86             if (!vis[v] && v != fa) {
     87                 dfsSz(v, u);
     88                 sz[u] += sz[v];
     89                 mx[u] = Math.max(mx[u], sz[v]);
     90             }
     91         }
     92     }
     93 
     94     private void dfsRoot(int r, int u, int fa)//r为子树的根
     95     {
     96         //子树的其余节点
     97         if (sz[r] - sz[u] > mx[u])
     98             mx[u] = sz[r] - sz[u];
     99         //root为重心
    100         if (mx[u] < MIN) {
    101             MIN = mx[u];
    102             root = u;
    103         }
    104         for (int i = 0; i < G.get(u).size(); i++) {
    105             int v = G.get(u).get(i).v;
    106             if (!vis[v] && v != fa)
    107                 dfsRoot(r, v, u);
    108         }
    109     }
    110 
    111     private void dfsDis(int u, int fa, int d) {
    112         //System.out.println("u:" + u +" fa:" + fa + " d:" + d);
    113         dis.add(d);
    114         for (int i = 0; i < G.get(u).size(); i++) {
    115             int v = G.get(u).get(i).v;
    116             int w = G.get(u).get(i).w;
    117             //System.out.println("i=" + i + " v=" + v);
    118             if (!vis[v] && v != fa)
    119                 dfsDis(v, u, d + w);
    120         }
    121     }
    122 
    123     private int cal(int r, int w) {
    124         int ret = 0;
    125         dis.clear();
    126         dfsDis(r, r, w);
    127         Collections.sort(dis);
    128         int L = 0, R = dis.size() - 1;
    129         while (L < R) {
    130             while (dis.get(L) + dis.get(R) > k && L < R) R--;
    131             ret += R - L;
    132             L++;
    133         }
    134         return ret;
    135     }
    136 }
    E java
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int N=1e5+5;
     5 vector< pair<int,int> >G[N];
     6 int mx[N],sz[N],vis[N],dis[N],ans,MIN,n,k,num,root;
     7 void dfssz(int u,int fa)
     8 {
     9     sz[u]=1;
    10     mx[u]=0;
    11     for(int i=0;i<G[u].size();i++)
    12     {
    13         int v=G[u][i].first;
    14         if(!vis[v]&&v!=fa)
    15         {
    16             dfssz(v,u);
    17             sz[u]+=sz[v];
    18             mx[u]=max(mx[u],sz[v]);
    19         }
    20     }
    21 }
    22 void dfsroot(int r,int u,int fa)//r为子树的根 
    23 {
    24     if(sz[r]-sz[u]>mx[u])//子树的其余节点 
    25         mx[u]=sz[r]-sz[u];
    26     if(mx[u]<MIN)//root为重心
    27         MIN=mx[u],root=u;
    28     for(int i=0;i<G[u].size();i++)
    29     {
    30         int v=G[u][i].first;
    31         if(!vis[v]&&v!=fa)
    32             dfsroot(r,v,u);
    33     }
    34 }
    35 void dfsdis(int u,int fa,int d)
    36 {
    37     dis[num++]=d;
    38     for(int i=0;i<G[u].size();i++)
    39     {
    40         int v=G[u][i].first;
    41         int w=G[u][i].second;
    42         if(!vis[v]&&v!=fa)
    43             dfsdis(v,u,d+w);
    44     }
    45 }
    46 int cal(int r,int w)
    47 {
    48     int ret=0;
    49     num=0;
    50     dfsdis(r,r,w);
    51     sort(dis,dis+num);
    52     int L=0,R=num-1;
    53     while(L<R)
    54     {
    55         while(dis[L]+dis[R]>k&&L<R)R--;
    56         ret+=R-L;    
    57         L++;
    58     }
    59     return ret;
    60 }
    61 void dfs(int u)
    62 {
    63     MIN=n;
    64     dfssz(u,u);
    65     dfsroot(u,u,u);
    66     int Grivate=root;
    67     ans+=cal(Grivate,0);
    68     vis[root]=1;
    69     for(int i=0;i<G[Grivate].size();i++)
    70     {
    71         int v=G[Grivate][i].first;
    72         int w=G[Grivate][i].second;
    73         if(!vis[v])
    74         {
    75             ans-=cal(v,w);
    76             dfs(v);
    77         }
    78     }
    79 }
    80 int main(){
    81     int m;
    82     scanf("%d%d",&n,&m);
    83     for(int i=1;i<=m;i++){
    84         int u,v,w;
    85         scanf("%d%d%d%*s",&u,&v,&w);
    86         G[u-1].push_back({v-1,w});
    87         G[v-1].push_back({u-1,w});
    88     }
    89     scanf("%d",&k);
    90     dfs(0);
    91     printf("%d",ans);
    92     return 0;
    93 }
    E C++

    F.最长连续子序列回到顶部

    题意

    求最长连续子序列使得和是7的倍数

    题解

    这样想,如果[1,i-1]模7为3,如果[1,j]模7也为3,那么就说明[i,j]模7为0

    dp[i]表示[1,i]的和模7的第一次出现的位置,那么答案就是后面出现的最大距离,复杂度O(n)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         int n = sc.nextInt();
     9         int[] dp = new int[8];
    10         int max = 0, sum = 0;
    11         for (int i = 1; i <= n; i++) {
    12             int x = sc.nextInt();
    13             sum = (sum + x) % 7;
    14             if (dp[sum] != 0)
    15                 max = Math.max(max, i - dp[sum]);
    16             if (dp[sum] == 0)
    17                 dp[sum] = i;
    18         }
    19         System.out.println(max);
    20     }
    21 }
    F

    G.Guessing Game回到顶部

    题意

    猜数字1-10,问出题的是否诚实

    题解

    根据too low和too high确定范围,根据right on判断是否在范围内,复杂度O(1)

    PS:java中Scanner的getLine方法会读回车,所以得先把回车读掉

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         while (sc.hasNext()) {
     9             Boolean[] vis = new Boolean[11];
    10             for (int i = 1; i <= 10; i++)
    11                 vis[i] = false;
    12             Boolean dishonest = true;
    13             int guass;
    14             while (true) {
    15                 guass = sc.nextInt();
    16                 if (guass == 0) break;
    17                 sc.nextLine();// 读回车
    18                 String s = sc.nextLine();
    19                 if ("too high".equals(s)) {
    20                     for (int i = guass; i <= 10; i++)
    21                         vis[i] = true;
    22                 } else if ("too low".equals(s)) {
    23                     for (int i = 1; i <= guass; i++)
    24                         vis[i] = true;
    25                 } else {
    26                     if (vis[guass]) dishonest = false;
    27                     break;
    28                 }
    29             }
    30             if (guass == 0) break;
    31             if (!dishonest) System.out.println("Stan is dishonest");
    32             else System.out.println("Stan may be honest");
    33         }
    34     }
    35 }
    G

    H.学习之我要直线回到顶部

    题意

    给你2<=n<=10^5个点,问是否存在两条平行直线穿过所有点

    题解

    首先当n<=3一定满足

    假设存在,那么取出三个点,点1,点2,点3,构造直线12,直线13,直线23,一定能够找到其中一条平行线

    为什么?如果1、2不是,那么要么13在平行线上,要么23在平行线上

    那么枚举12,13,23把直线上的点都去掉,再看身下的点是否在一条直线上并平行,复杂度O(n)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         Solution solver = new Solution();
     9         while (sc.hasNext()) {
    10             solver.solve(sc);
    11         }
    12     }
    13 
    14 }
    15 
    16 class Solution {
    17 
    18     private int[] x = new int[100005];
    19     private int[] y = new int[100005];
    20     private boolean[] vis = new boolean[100005];
    21     private int n;
    22 
    23     public void solve(Scanner sc) {
    24         n = sc.nextInt();
    25         for (int i = 0; i < n; i++) {
    26             x[i] = sc.nextInt();
    27             y[i] = sc.nextInt();
    28         }
    29         if ( n <= 3 || pd(0,1) || pd(0,2) || pd(1,2)) System.out.println("YES");
    30         else System.out.println("NO");
    31     }
    32 
    33     private boolean pd(int sPoint1, int sPoint2) {
    34         for (int i = 0; i < n; i++) vis[i] = false;
    35         int cnt = n;
    36         // 第一条线
    37         for (int i = 0; i < n; i++) if (check(sPoint1, sPoint2, i)) {
    38             vis[i] = true;
    39             cnt--;
    40         }
    41         if (cnt == 0) return true;
    42         for (int i = 0; i < n; i++) {
    43             if (!vis[i]) {
    44                 // 第二条线
    45                 vis[i] = true;
    46                 cnt--;
    47                 for (int j = i + 1; j < n; j++) if (!vis[j] && checkParallel(sPoint1, sPoint2, i, j)) {
    48                     vis[j] = true;
    49                     cnt--;
    50                 }
    51                 return cnt == 0;
    52             }
    53         }
    54         return false;
    55     }
    56 
    57     // 检查i,j,k是否三点共线
    58     private boolean check(int i, int j, int k) {
    59         return (long)(x[j] - x[i]) * (y[k] - y[i]) == (long)(x[k] - x[i]) * (y[j] - y[i]);
    60     }
    61 
    62     // 检查i,j和k,l是否平行
    63     private boolean checkParallel(int i, int j, int k, int l) {
    64         return (long)(x[j] - x[i]) * (y[l] - y[k]) == (long)(x[l] - x[k]) * (y[j] - y[i]);
    65     }
    66 
    67 }
    H

    I.查询数据回到顶部

    题意

    n个数,m次查询,每次查询一个数是否存在

    题解

    hashset,复杂度O(Σm)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         int n = sc.nextInt();
     9         int m = sc.nextInt();
    10         HashSet<Integer> hashSet = new HashSet<Integer>();
    11         for (int i = 0; i < n; i++) {
    12             hashSet.add(sc.nextInt());
    13         }
    14         for (int i = 0; i < m; i++) {
    15             if (hashSet.contains(sc.nextInt())) {
    16                 System.out.println("Yes");
    17             } else {
    18                 System.out.println("No");
    19             }
    20         }
    21     }
    22 }
    I

    J.切蛋糕回到顶部

    题意

    每次竖直切一刀,求切n刀后可以把蛋糕分成几块

    题解

    由于大小不需要一样,那么第i+1刀肯定与前i刀都有交点,即多出i+1块,那么就变成等差数列求和,复杂度O(1)

    代码

     1 import java.util.*;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         Scanner sc = new Scanner(System.in);
     8         while(sc.hasNext()) {
     9             int n = sc.nextInt();
    10             System.out.println(1 + (1 + n) * n / 2);
    11         }
    12     }
    13 }
    J
  • 相关阅读:
    airtest支持Cocos-Creator,SDK接入
    Python的getter和setter方法
    liunx常用命令
    liunx的vim常用命令收集
    django+atx+liunx的一些shell脚本
    django+airtest+atx部署liunx平台
    Android下的鉴权实现方案
    Mate20 pro实现H265 (HEVC)实时硬件编码
    OpenCV C++常用功能介绍
    Ubuntu16.04编译libjpeg-turbo库
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/12679289.html
Copyright © 2011-2022 走看看