这时2016 Pacific Northwest RC的题目

颓了几天感觉当初这套题不错,补完啦(UPD)

gym101201A

签到题,读对题即可

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 char a[100];
 6 int f[100],n,ans;
 7 int main()
 8 {
 9     scanf("%s",a+1);
10     n=strlen(a+1);
11     f[1]=0;
12     for (int i=1; i<=n; i++)
13     {
14         for (int j=i; j; j--)
15             if (a[i]>a[j]) f[i]=max(f[i],f[j]);
16         f[i]++;
17         if (f[i]>ans) ans=f[i];
18     }
19     printf("%d\n",26-ans);
20 }
View Code

 

gym101201B

一类类似spfa的dp,用f[x][y][k]表示到指令符第k位走到(x,y)所需要的修改次数

然后用spfa的形式进行转移即可(训练的时候简直不知道自己在写什么)

 1 #include<bits/stdc++.h>
 2 #define mp make_pair
 3 #define pi pair<int,int>
 4 using namespace std;
 5 const int dx[4]={-1,1,0,0};
 6 const int dy[4]={0,0,-1,1};
 7 int f[60][60][60],v[60][60],a[60][60],bx,by,ex,ey,n,m,l;
 8 pi q[2000010];
 9 char s[60];
10 
11 void bfs(int k)
12 {
13     int h=1,r=0;
14     for (int i=1; i<=n; i++)
15         for (int j=1; j<=m; j++)
16             if (a[i][j])
17             {
18                 q[++r]=mp(i,j);
19                 v[i][j]=1;
20             }
21 
22     while (h<=r)
23     {
24         int i=q[h].first,j=q[h].second;
25         v[i][j]=0; h++;
26         for (int w=0; w<4; w++)
27         {
28             int x=i+dx[w],y=j+dy[w];
29             if (!a[x][y]) continue;
30             if (f[x][y][k]>f[i][j][k]+1)
31             {
32                 f[x][y][k]=f[i][j][k]+1;
33                 if (!v[x][y])
34                 {
35                     q[++r]=mp(x,y);
36                     v[x][y]=1;
37                 }
38             }
39         }
40     }
41 }
42 
43 int main()
44 {
45     scanf("%d%d",&n,&m);
46     for (int i=1; i<=n; i++)
47     {
48         scanf("%s",s+1);
49         for (int j=1; j<=m; j++)
50         {
51             if (s[j]!='#') a[i][j]=1;
52             if (s[j]=='R')
53             {
54                 bx=i;
55                 by=j;
56             }
57             if (s[j]=='E')
58             {
59                 ex=i;
60                 ey=j;
61             }
62         }
63     }
64     scanf("%s",s+1);
65     l=strlen(s+1);
66     for (int i=1; i<=n; i++)
67         for (int j=1; j<=m; j++)
68             for (int k=0; k<=l+1; k++) f[i][j][k]=1e9;
69     int ans=1e9;
70     f[bx][by][0]=0;
71     for (int k=1; k<=l+1; k++)
72     {
73         bfs(k-1);
74         ans=min(ans,f[ex][ey][k-1]);
75         if (k==l+1) break;
76         for (int i=1; i<=n; i++)
77             for (int j=1; j<=m; j++)
78                 if (a[i][j])
79                 {
80                     int pw;
81                     if (s[k]=='L') pw=2;
82                     if (s[k]=='R') pw=3;
83                     if (s[k]=='U') pw=0;
84                     if (s[k]=='D') pw=1;
85                     int x=i+dx[pw],y=j+dy[pw];
86                     if (a[x][y]) f[x][y][k]=min(f[i][j][k-1],f[x][y][k]);
87                     else f[i][j][k]=min(f[i][j][k-1],f[i][j][k]);
88                     f[i][j][k]=min(f[i][j][k-1]+1,f[i][j][k]);
89                 }
90     }
91     printf("%d\n",ans);
92 }
View Code

 

gym101201C

简单贪心即可

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 int v[100010],s,ans,n,m,k;
 5 int main()
 6 {
 7     scanf("%d%d%d",&n,&m,&k);
 8     for (int i=1; i<=m; i++)
 9     {
10         int x;
11         scanf("%d",&x);
12         v[x]=1;
13     }
14     for (int i=1; i<=k; i++)
15         s+=v[i];
16     if (s<=1)
17     {
18         int j=k;
19         while (j&&v[j]) j--;
20         v[j]=1; ans++; s++;
21         if (s<=1)
22         {
23             while (j&&v[j]) j--;
24             v[j]=1; ans++; s++;
25         }
26     }
27     for (int i=k+1; i<=n; i++)
28     {
29         s=s-v[i-k]+v[i];
30         if (s<=1)
31         {
32             int j=i;
33             while (j>i-k&&v[j]) j--;
34             v[j]=1; ans++; s++;
35             if (s<=1)
36             {
37                 while (j>i-k&&v[j]) j--;
38                 v[j]=1; ans++; s++;
39             }
40         }
41     }
42     printf("%d\n",ans);
43 }
View Code

 

gym101201D

首先假设做题顺序是i1,i2...in,那么最后罚时是n*t(i1)+(n-1)*t(i2)+...t(in)

考虑罚时的期望,根据期望的线性性质,如果第i道题期望在Pi时解决,那么它对期望的贡献就是(n-Pi)*ti

现在求所有可能罚时的总和,也就是我们只要求出每个题目的位置总贡献((n-Pi)*n!)即可

观察阅读规则,对于每道题什么时候读,我们只要考虑比这道题容易或难的题的数目

所以对第x道题,我们令f[i][j][p][r] 表示有i道比x简单的题还未读,j道比x难的题,p表示x有没有读,r表示当前读过r道比x简单的题,在这种情况下的位置总贡献

(耗时相同的我们随便假定一个难以顺序,因为我们只在乎最后总的贡献)

 根据阅读规则很容易写出转移方程,具体见程序

又观察可得,在每个固定状态下,不论是针对哪道题,f[]是不变的即通用的,因此总的复杂度为O(n^3)

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 const int mo=1e9+7;
 6 int f[320][320][2][320];
 7 ll d[320];
 8 int a[320],n,k;
 9 
10 void inc(int &a,int b)
11 {
12     a+=b;
13     if (a>mo) a-=mo;
14 }
15 
16 int dp(int i,int j,int p,int r)
17 {
18     if (f[i][j][p][r]!=-1) return f[i][j][p][r];
19     int s=-1,rr=r;
20     if (i+j+p==0) s=k-r; //所有题都读过了
21     else if (i+j+p<=n-k) //读过的题超过了k道
22     {
23         if (r) rr--; //先做最简单的
24         else if (p==0) s=(i+j+k)*d[i+j]%mo;  //做当前考虑的这道并计算总的贡献
25     }
26     if (s==-1)
27     {
28         s=0; //三种可能的读题情况
29         if (i) s=1ll*i*dp(i-1,j,p,rr+1)%mo; 
30         if (j) inc(s,1ll*j*dp(i,j-1,p,rr)%mo);
31         if (p) inc(s,dp(i,j,p-1,rr)%mo);
32     }
33     f[i][j][p][r]=s;
34     return s;
35 }
36 
37 int main()
38 {
39     memset(f,255,sizeof(f));
40     d[0]=1;
41     scanf("%d%d",&n,&k);
42     for (int i=1; i<=n; i++)
43         d[i]=d[i-1]*i%mo;
44     for (int i=1; i<=n; i++)
45         scanf("%d",&a[i]);
46     sort(a+1,a+n+1);
47     int ans=0;
48     for (int i=1; i<=n; i++)
49         ans=(ans+1ll*a[i]*dp(i-1,n-i,1,0)%mo)%mo;
50     printf("%d\n",ans);
51 }
View Code

 

gym101201E

好题,首先求出原先控制区域的凸包

如果把问题一般化处理,就是求凸包插入一个点怎么变

对于每一颗新增点i,凸包面积如果发生变化,一定是从凸包上两点l,r连向i

i-r,i-l两条射线刚好能卡住原凸包,且原先凸包上l~r之间的点不再是边界

根据凸包面积计算公式,如果我们找到l,r,那么很容易用前缀和求出答案

为了寻找l,r,我们假定p1为凸包最左下的点,pm为凸包最右上的点

考虑i的位置,分4种情况

1. i在p1的左侧 2. i在pm的右侧

3. i在p1,pm之间且在p1,pm连线的上方

4. i在p1,pm之间且在p1,pm连线的下方

情况1和情况2类似且较为简单,l,r一定分别在凸包的上凸壳和下凸壳上(也可能正好是p1,pm)

根据i-r,i-l两条射线刚好能卡住原凸包的性质可以用二分快速找到

情况3和情况4显然,l,r会同时落在上凸壳或下凸壳上,我们需要找到一个凸包的分界点k

使得x[k-1]<x[i]<=x[k],这显然是可以用二分求出的,再在上(下)凸壳的左右区间分别用二分找到l,r即可

示意图如下:

其实,还有一个更简单的方法

可以证明,如果要是新的凸包面积最大,那么增加的点应在整个点集的凸包上

随着点在凸包上的逆时针(或顺时针移动),其对应的l,r也在凸包上做同向移动,由此就是two pointer的问题了

但是写起来似乎很有细节问题,改日把这个方法补上

另外注意这题答案会很大,double精度不够,又答案只有一位小数,直接判断着输出即可

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 typedef long long ll;
  5 struct po
  6 {
  7     int x,y;
  8     friend bool operator <(po a,po b)
  9     {
 10         if (a.x==b.x) return a.y<b.y;
 11         return a.x<b.x;
 12     }
 13     friend po operator -(po a,po b)
 14     {
 15         return (po){a.x-b.x,a.y-b.y};
 16     }
 17     friend po operator +(po a,po b)
 18     {
 19         return (po){a.x+b.x,a.y+b.y};
 20     }
 21     friend ll operator *(po a, po b)
 22     {
 23         return 1ll*a.x*b.y-1ll*a.y*b.x;
 24     }
 25 } p[100010],q[100010];
 26 int n,k,t;
 27 ll s[100010];
 28 
 29 int get(int l,int r,int i,int w)
 30 {
 31     while (l<r)
 32     {
 33         int m=(l+r)>>1;
 34         if ((q[m]-p[i])*(q[m+1]-p[i])*w>0) r=m;
 35         else l=m+1;
 36     }
 37     return l;
 38 }
 39 
 40 int bord(int l,int r,int i,int w)
 41 {
 42     while (l<r)
 43     {
 44         int m=(l+r)>>1;
 45         if ((q[m].x-p[i].x)*w<0) l=m+1;
 46         else r=m;
 47     }
 48     return l;
 49 }
 50 
 51 int main()
 52 {
 53     scanf("%d%d",&n,&k);
 54     for (int i=1; i<=n; i++)
 55         scanf("%d%d",&p[i].x,&p[i].y);
 56     sort(p+1,p+1+k);
 57     q[1]=p[1]; t=1;
 58     for (int i=2; i<=k; i++)
 59     {
 60         while (t>1&&(p[i]-q[t-1])*(q[t]-q[t-1])>=0) t--;
 61         q[++t]=p[i];
 62     }
 63     int m=t;
 64     for (int i=k-1;i;i--)
 65     {
 66         while (t>m&&(p[i]-q[t-1])*(q[t]-q[t-1])>=0) t--;
 67         q[++t]=p[i];
 68     }
 69     for (int i=1; i<t; i++)
 70         s[i+1]+=s[i]+q[i]*q[i+1];
 71     ll ans=s[t],tmp;
 72     for (int i=k+1; i<=n; i++)
 73     {
 74         if (p[i].x<q[1].x)
 75         {
 76             int l=get(1,m,i,1), r=get(m,t,i,-1);
 77             tmp=s[r]-s[l]+q[r]*p[i]+p[i]*q[l];
 78         }
 79         else if (p[i].x>q[m].x)
 80         {
 81             int l=get(1,m,i,-1),r=get(m,t,i,1);
 82             tmp=s[t]-s[r]+s[l]+q[l]*p[i]+p[i]*q[r];
 83         }
 84         else if ((q[m]-q[1])*(p[i]-q[1])>0)
 85         {
 86             int mid=bord(m,t,i,-1);
 87             if (mid>m&&(q[mid]-q[mid-1])*(p[i]-q[mid-1])>0) continue;
 88             int l=mid>m?get(m,mid-1,i,-1):m;
 89             int r=get(mid,t,i,1);
 90             tmp=s[t]-s[r]+s[l]+q[l]*p[i]+p[i]*q[r];
 91         }
 92         else {
 93             int mid=bord(1,m,i,1);
 94             if (mid>1&&(q[mid]-q[mid-1])*(p[i]-q[mid-1])>0) continue;
 95             int l=(mid>1)?get(1,mid-1,i,-1):1;
 96             int r=get(mid,m,i,1);
 97             tmp=s[t]-s[r]+s[l]+q[l]*p[i]+p[i]*q[r];
 98         }
 99         ans=max(ans,tmp);
100     }
101     printf("%lld",ans/2);
102     if (ans&1) puts(".5"); else puts(".0");
103 }
方法一

 

gym101201F

把每个灯照行还是列看作状态,任意两个同行(或同列)的灯不能同时照同行(或同列)

——经典的2sat问题

 1 #include<bits/stdc++.h>
 2 #define mp make_pair
 3 #define pi pair<int,int>
 4 #define fi first
 5 #define se second
 6 using namespace std;
 7 vector<int> g[2010];
 8 int x[1010],y[1010],f[2010],dfn[2010],low[2010],st[2010],n,r,l,h,t,s,m,be[2010];
 9 pi q[2010];
10 void tarjan(int x)
11 {
12      dfn[x]=low[x]=++h;
13      st[++t]=x;
14      f[x]=1;
15      for (int i=0; i<g[x].size(); i++)
16      {
17          int y=g[x][i];
18          if (!dfn[y])
19          {
20             tarjan(y);
21             low[x]=min(low[x],low[y]);
22          }
23          else if (f[y]) low[x]=min(low[x],low[y]);
24      }
25      if (low[x]==dfn[x])
26      {
27         s++;
28         while (st[t+1]!=x)
29         {
30             int y=st[t--];
31             be[y]=s; f[y]=0;
32         }
33      }
34 }
35 
36 int main()
37 {
38     scanf("%d%d%d",&n,&r,&m);
39     for (int i=1; i<=m; i++)
40         scanf("%d%d",&x[i],&y[i]);
41 
42     for (int i=1; i<=m; i++)
43         for (int j=1; j<=m; j++)
44             if (i!=j)
45             {
46                 if (x[i]==x[j]&&abs(y[i]-y[j])<=2*r)
47                 {
48                     g[i+m].push_back(j);
49                     g[j+m].push_back(i);
50                 }
51                 if (y[i]==y[j]&&abs(x[i]-x[j])<=2*r)
52                 {
53                     g[i].push_back(j+m);
54                     g[j].push_back(i+m);
55                 }
56             }
57 
58     for (int i=1; i<=m*2; i++)
59         if (!dfn[i])
60         {
61             h=t=0;
62             tarjan(i);
63         }
64 
65     for (int i=1; i<=m; i++)
66         if (be[i]==be[i+m])
67         {
68             puts("NO");
69             return 0;
70         }
71     puts("YES");
72 }
View Code

 

gym101201G

首先把确定的拎出来,不确定的地方要使海岛尽可能多,那必定是将一格作为一个海岛

不难想到将图黑白染色做而二分图的最大独立集

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int dx[4]={-1,1,0,0};
 5 const int dy[4]={0,0,-1,1};
 6 char s[100];
 7 int f[1610],b[60][60],a[60][60],v[60][60],cy[1610],cx[1610],n,m,ans,t;
 8 vector<int> g[1610];
 9 void dfs(int i,int j)
10 {
11     v[i][j]=1;
12     for (int k=0; k<4; k++)
13     {
14         int x=i+dx[k],y=j+dy[k];
15         if (x==0||x>n||y>m||y==0) continue;
16         if (v[x][y]) continue;
17         if (a[x][y]==-1) a[x][y]=0;
18         if (a[x][y]==1) dfs(x,y);
19     }
20 }
21 
22 int work(int x)
23 {
24     for (int i=0; i<g[x].size(); i++)
25     {
26         int y=g[x][i];
27         if (!f[y])
28         {
29             f[y]=1;
30             if (!cy[y]||work(cy[y]))
31             {
32                 cx[x]=y;
33                 cy[y]=x;
34                 return 1;
35             }
36         }
37     }
38     return 0;
39 }
40 
41 int main()
42 {
43     //freopen("1.in","r",stdin);
44     scanf("%d%d",&n,&m);
45     for (int i=1; i<=n; i++)
46     {
47         scanf("%s",s+1);
48         for (int j=1; j<=m; j++)
49         {
50             if (s[j]=='W') a[i][j]=0;
51             if (s[j]=='C') a[i][j]=-1;
52             if (s[j]=='L') a[i][j]=1;
53         }
54     }
55     for (int i=1; i<=n; i++)
56         for (int j=1; j<=m; j++)
57             if (!v[i][j]&&a[i][j]==1)
58             {
59                 ans++;
60                 dfs(i,j);
61             }
62 
63     for (int i=1; i<=n; i++)
64         for (int j=1; j<=m; j++)
65             if (a[i][j]==-1) b[i][j]=++t;
66     for (int i=1; i<=n; i++)
67         for (int j=1; j<=m; j++)
68             if ((i+j)%2==0)
69             {
70                 for (int k=0; k<4; k++)
71                 {
72                     int x=i+dx[k],y=j+dy[k];
73                     if (b[x][y]) g[b[i][j]].push_back(b[x][y]);
74                 }
75             }
76     int s=0;
77     for (int i=1; i<=t; i++)
78         if (g[i].size())
79         {
80             if (!cx[i])
81             {
82                 memset(f,0,sizeof(f));
83                 s+=work(i);
84             }
85         }
86     printf("%d\n",ans+t-s);
87 }
View Code

 

gym101201H

经典的区间最大不重合拼接问题,离散化后树状数组优化dp

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 struct node{ll l,r;} a[200010];
 6 ll n,ans,c[400010],b[400010];
 7 int sz,m,t;
 8 bool cmp(node a,node b)
 9 {
10     return a.r<b.r;
11 }
12 
13 ll ask(int x)
14 {
15     ll s=0;
16     for (int i=x; i; i-=i&(-i))
17         s=max(s,c[i]);
18     return s;
19 }
20 
21 void work(int x,ll w)
22 {
23     for (int i=x; i<=sz; i+=i&(-i))
24         c[i]=max(c[i],w);
25 }
26 
27 int main()
28 {
29     scanf("%lld%d",&n,&m);
30     for (int i=1; i<=m; i++)
31     {
32         scanf("%lld%lld",&a[i].l,&a[i].r);
33         b[++t]=a[i].l;
34         b[++t]=a[i].r;
35     }
36     sort(a+1,a+1+m,cmp);
37     sort(b+1,b+1+t);
38     sz=unique(b+1,b+1+t)-b-1;
39     ll ans=0;
40     for (int i=1; i<=m; i++)
41     {
42         int x=lower_bound(b+1,b+1+sz,a[i].l)-b;
43         int y=lower_bound(b+1,b+1+sz,a[i].r)-b;
44         ll tmp=ask(x-1)+a[i].r-a[i].l+1;
45         ans=max(ans,tmp);
46         work(y,tmp);
47     }
48     printf("%lld\n",n-ans);
49 }
View Code

 

gym101201I

这题想了半天简直蠢,贪心

每次肯定送尽可能最远的最优,然后做一些计算即可

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 struct node{int x,c;} a[100010];
 6 bool cmp(node a,node b)
 7 {
 8     return a.x<b.x;
 9 }
10 ll ans;
11 int n,k;
12 int main()
13 {
14     scanf("%d%d",&n,&k);
15     for (int i=1; i<=n; i++)
16         scanf("%d%d",&a[i].x,&a[i].c);
17     sort(a+1,a+1+n,cmp);
18     int i=n;
19     while (i)
20     {
21         if (a[i].x<0) break;
22         ll ti=(a[i].c+k-1)/k;
23         ans+=abs(a[i].x)*ti;
24         ll s=ti*k;
25         while (i&&a[i].x>=0&&s)
26         {
27             if (a[i].c<=s)
28             {
29                 s-=a[i].c;
30                 i--;
31             }
32             else {
33                 a[i].c-=s;
34                 break;
35             }
36         }
37     }
38     i=1;
39     while (i<=n)
40     {
41         if (a[i].x>0) break;
42         ll ti=(a[i].c+k-1)/k;
43         ans+=abs(a[i].x)*ti;
44         ll s=ti*k;
45         while (i<=n&&a[i].x<0&&s)
46         {
47             if (a[i].c<=s)
48             {
49                 s-=a[i].c;
50                 i++;
51             }
52             else {
53                 a[i].c-=s;
54                 break;
55             }
56         }
57     }
58     printf("%lld\n",ans*2);
59 }
View Code

 

gym101201J

一道训练时大量人通过我不会的题……

多次询问一个数依次对区间每个数取模的结果

考虑到每次取模,如果x>a[i]那x%a[i]<=x/2,因此最多模log级别的数

我们每次模完当前数,只要找下面第一个小于x的数即可

这可以用二分+st表预处理区间最小值解决,复杂度是log方的

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 int l2[1200010],d[25],n,q;
 6 ll f[200010][20],a[200010];
 7 ll ask(int l,int r)
 8 {
 9     int k=l2[r-l+1];
10     return min(f[l][k],f[r-d[k]+1][k]);
11 }
12 
13 ll get(int l,int r,ll v)
14 {
15     int s=n+1;
16     while (l<=r)
17     {
18         int m=(l+r)>>1;
19         if (ask(l,m)>v) l=m+1;
20         else {
21             s=m;
22             r=m-1;
23         }
24     }
25     return s;
26 }
27 
28 int main()
29 {
30     d[0]=1;
31     for (int i=1; i<=20; i++)
32     {
33         d[i]=d[i-1]*2;
34         for (int j=(1<<(i-1)); j<(1<<i); j++)
35             l2[j]=i-1;
36     }
37     scanf("%d%d",&n,&q);
38     for (int i=1; i<=n; i++)
39     {
40         scanf("%lld",&a[i]);
41         f[i][0]=a[i];
42     }
43     for (int j=1; (1<<j)<n; j++)
44         for (int i=1; i<=n; i++)
45             if (i+d[j]-1<=n) f[i][j]=min(f[i][j-1],f[i+d[j-1]][j-1]);
46             else break;
47 
48     for (int i=1; i<=q; i++)
49     {
50         ll v; int l,r;
51         scanf("%lld%d%d",&v,&l,&r);
52         while (l<=r)
53         {
54             v%=a[l];
55             if (!v) break;
56             l=get(l+1,r,v);
57         }
58         printf("%lld\n",v);
59     }
60 }
View Code

 

gym101201K

又一道训练时大量人通过我不会的题+1

其实是一道很简单的题,最重要的一点是最后的期望胜场数=∑至少胜i场的概率*i

那么在2^i的区间脱颖而出,概率显然是C(2^k-r,2^i-1) / C(2^k,2^i-1)

注意一下精度问题

 1 #include<bits/stdc++.h>
 2 int k,n,m,r;
 3 
 4 int main()
 5 {
 6     scanf("%d%d",&k,&r);
 7     n=(1<<k)-1; m=(1<<k)-r;
 8     double p=1.0,ans=0;
 9     for (int k=1; (1<<k)-1<=m; k++)
10     {
11         int sm=m-(1<<k)+2, em=m-(1<<(k-1))+1;
12         int sn=n-(1<<k)+2;
13         for (int mm=sm,nn=sn; mm<=em; mm++,nn++)
14             p*=1.0*mm/nn;
15         ans+=p;
16     }
17     printf("%.5lf\n", ans);
18 }
View Code

 

gym101201L

很有趣的构造题,首先结论是一定有解

方法如下:首先我们选定一个一定在点集凸包上的点(不妨就是左下的点)

那么它在点集凸包上有两个相邻的点,把凸包内作为点的朝向的话

如果当前指令要求是L即逆时针的话,下一个点是当前点的当前凸包右相邻点,否则反之

首先由凸包性质知,这样走一定满足转向要求,并且每次要走的点都是当前未走过点的凸包上的点

这样每次我们走的都是凸包上的一条边,这样一定不会存在相交的情况

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 struct po
 5 {
 6     int x,y;
 7     friend bool operator <(po a,po b)
 8     {
 9         if (a.x==b.x) return a.y<b.y;
10         return a.x<b.x;
11     }
12     friend po operator -(po a,po b)
13     {
14         return (po){a.x-b.x,a.y-b.y};
15     }
16     friend int operator *(po a, po b)
17     {
18         return a.x*b.y-a.y*b.x;
19     }
20 } p[1010];
21 int ans[1010],n;
22 char s[1010];
23 
24 int main()
25 {
26     scanf("%d",&n);
27     for (int i=1; i<=n; i++)
28     {
29         scanf("%d%d",&p[i].x,&p[i].y);
30         ans[i]=i;
31     }
32     int j=1;
33     for (int i=2; i<=n; i++)
34         if (p[i]<p[j]) j=i;
35     swap(p[1],p[j]);
36     swap(ans[1],ans[j]);
37     scanf("%s",s+2);
38     for (int i=2; i<n; i++)
39     {
40         int k=i,x=(s[i]=='L')?1:-1;
41         for (int j=i+1; j<=n ;j++)
42             if ((p[k]-p[i-1])*(p[j]-p[i-1])*x<0) k=j;
43         swap(p[i],p[k]);
44         swap(ans[i],ans[k]);
45     }
46     for (int i=1; i<=n; i++)
47     {
48         printf("%d",ans[i]);
49         if (i==n) puts(""); else printf(" ");
50     }
51 }
View Code

 

posted on 2017-07-06 22:45  acphile  阅读(647)  评论(0编辑  收藏  举报