zoukankan      html  css  js  c++  java
  • 4.29训练题解

    这时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
    ",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
    ",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
    ",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
    ",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
    ",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-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
    ",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
    ",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
    ", 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
  • 相关阅读:
    【CF580D】Kefa and Dishes
    【poj3311】Hie with the Pie
    校外实习-7.7
    校外实习-7.6
    校外实习-7.5
    校外实习-7.4
    作业九-课程总结(补充)
    作业九-课程总结
    作业四——结对编程四则运算
    作业三
  • 原文地址:https://www.cnblogs.com/phile/p/7128749.html
Copyright © 2011-2022 走看看