2017.09.03校内训练

Posted lazytear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017.09.03校内训练相关的知识,希望对你有一定的参考价值。

T1:卡片

题解:这很明显,是一道选择题!!!

我们考虑每一种情况:只有一种卡片时,很显然最后剩下的只能是这一种;有三种卡片时,可以变成各只有一张,无论选取哪两张,都可以变成剩下的那一张,因此每一种都可以剩下;有两种的情况:若这两种都有两张以上,便可以各取一张合成没有的那一种,最后结果请参见上一条;若有一种只有一张,另一种有多张,则每一次的转化操作都要使用到较多的那种一张,不论如何都不可能合成较多张的那一种。因此结果是除了多于一张的那一种以外的其它两种;若这两种各只有一张,则结果必定是没有的那一种。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 struct node{
 9     char ki;
10     int num;
11 }card[5];
12 int n,kind=0;
13 bool c[5]={};
14 char s[210];
15 int main(){
16     freopen("card.in","r",stdin);
17     freopen("card.out","w",stdout);
18     scanf("%d",&n);
19     scanf("%s",s);
20     int i,j;
21     card[1].ki=\'B\';card[2].ki=\'G\';card[3].ki=\'R\';
22     card[1].num=0;card[2].num=0;card[3].num=0;
23     int x;
24     for(i=0;i<n;++i){
25         if(s[i]==\'B\')  x=1;
26         if(s[i]==\'G\')  x=2;
27         if(s[i]==\'R\')  x=3;
28         if(card[x].num==0)  kind++;
29         card[x].num++;
30     }
31     if(kind==3){
32         printf("BGR\\n");
33         return 0;
34     }
35     if(kind==1){
36         if(card[1].num>0)  printf("B\\n");
37         if(card[2].num>0)  printf("G\\n");
38         if(card[3].num>0)  printf("R\\n");
39         return 0;
40     }
41     if(kind==2){
42         int a,b;
43         if(card[1].num>0){
44             a=1;
45             if(card[2].num>0)  b=2;
46             else  b=3;
47         }
48         else{
49             a=2;b=3;
50         }
51         if(card[a].num>=2 && card[b].num>=2){
52             printf("BGR\\n");
53             return 0;
54         }
55         if(card[a].num==1 && card[b].num==1){
56             for(i=1;i<=3;++i){
57                 if(card[i].num==0){
58                     printf("%c\\n",card[i].ki);
59                     return 0;
60                 }
61             }
62         }
63         for(i=1;i<=3;++i){
64             if(card[i].num<=1)  c[i]=true;
65         }
66         for(i=1;i<=3;++i){
67             if(c[i]==true){
68                 printf("%c",card[i].ki);
69             }
70         }
71         printf("\\n");
72     }
73     return 0;
74 }
card.cpp

 T2:取数

题解:我们注意到:取奇数个数的数一定不会比再取一个偶数的结果更劣。而计算平均数的复杂度很高。因此我们考虑枚举中位数。而取一个中位数,在一个递增序列中,它左边的数应当尽量靠近它,右边的数应当尽量远离它。因此我们由题目可以得出:可以对于每一个位置三分这个位置的最优解/较优解并更新答案即可。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #define ll long long
 8 using namespace std;
 9 int n;
10 ll maxw,maxl,l,r,wa,wb;
11 int a[200010];
12 ll pre[200010];
13 double va,vb,v,ans=-1;
14 double getans(int w,int l){
15     ll sum=0;
16     sum+=pre[w]-pre[w-l-1];
17     sum+=pre[n]-pre[n-l];
18     return (double)sum/(double)(2*l+1)-(double)a[w];
19 }
20 int main(){
21     freopen("win.in","r",stdin);
22     freopen("win.out","w",stdout);
23     scanf("%d",&n);
24     int i,j,k;
25     for(i=1;i<=n;++i){
26         scanf("%d",&a[i]);
27     }
28     sort(a+1,a+n+1);
29     pre[0]=0;
30     for(i=1;i<=n;++i){
31         pre[i]=pre[i-1]+a[i];
32     }
33     if(n<=2){
34         printf("0.00\\n");return 0;
35     }
36     for(i=1;i<=n;++i){
37         l=0;r=min(i-1,n-i);
38         while(l+1<=r){
39             wa=l+(r-l)/3;
40             wb=r-(r-l)/3;
41             va=getans(i,wa);
42             vb=getans(i,wb);
43             if(va>vb){
44                 r=wb-1;
45             }
46             else  l=wa+1;
47         }
48         v=getans(i,l);
49         if(v>ans){
50             ans=v;
51             maxw=i;
52             maxl=l;
53         }
54     }
55     printf("%.2lf",ans);
56     return 0;
57 }
win.cpp

T3:密码

题解:我们注意到,因为可能出现的密码种类只有10000种。所以我们先用O(10L)的时间来预处理出对于每一位向后的第一个某数字的位置。之后在O(10000)的时间内枚举密码,对于每一个密码,可以在O(n)的时间里check,最后统计进模板里即可。

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 char ch[1000010];
 9 int l[1010];
10 int n,a,b;
11 int f[1000010][20]; 
12 int main(){
13     freopen("key.in","r",stdin);
14     freopen("key.out","w",stdout);
15     int i,w,h,z,j;
16     scanf("%d",&n);
17     l[0]=0;
18     for(i=1;i<=n;++i){
19         scanf("%d%s",&l[i],ch+l[i-1]);
20         l[i]+=l[i-1];
21     }
22     for(i=0;i<=9;++i)  f[l[n]][i]=l[n];
23     for(i=l[n]-1;i>=0;--i){
24         memcpy(f[i],f[i+1],sizeof f[i+1]);
25         f[i][ch[i]-48]=i;
26     }
27     a=0;b=0;
28     for(w=0;w<=9;++w){
29         for(h=0;h<=9;++h){
30             for(z=0;z<=9;++z){
31                 for(j=0;j<=9;++j){
32                     for(i=0;i<n;++i){
33                         if(f[f[f[f[l[i]][w]][h]][z]][j]<l[i+1])  ++a;
34                         else  break ;
35                     }
36                     b+=a/n;a=0;
37                 }
38             }
39         }
40     }
41     printf("%d\\n",b);
42     return 0;
43 }
key.cpp

T4:三角之恋

题解:我们可以从题目中看出这些信息:由于我们所要加入平面中的三角形都是等腰直角三角形,因此对于每一个单位长度的正方形,若其被覆盖,则只会存在两种情况:完全覆盖与过对角线覆盖一半。因此我们考虑采用离散化+扫描线的方式做。

      首先我们需要离散每个三角形的(x,y),(x+m,y),(x,y+m)三个点,便于后面计算答案。

      然后我们将每个三角形记作一个只有底部线段,并且右端点不断向左端点缩小的线段。在更新时直接暴力排序并且剔除会被某个其他线段覆盖的线段,然后将y坐标不断向上推,在过程中暴力计算每个离散长方形的面积,如果某个长方形没有被完全覆盖,那么就减去没覆盖的部分的面积。这样就可以在O(n2)的时间复杂度内计算出答案。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<cmath>
  7 #define ll long long
  8 using namespace std;
  9 struct node{
 10     int x,y,m,xb,tx,ty;
 11 }tri[5010];
 12 int n,lx,ly,ls,th;
 13 int x[10010],y[10010];
 14 node s[10010];
 15 bool u[10010];
 16 ll ans;
 17 bool cmp(node a,node b){
 18     if(a.y!=b.y)  return a.y<b.y;
 19     if(a.x!=b.x)  return a.x<b.x;
 20     return a.tx<b.tx;
 21 }
 22 void work(){
 23     int to=y[th+1]-y[th],r;
 24     int i,j=1;
 25     for(i=s[1].x;x[i]<=s[ls].xb;++i){
 26         while(j<ls && i>=s[j+1].x)  ++j;
 27         if(x[i]>=s[j].xb)  continue ;
 28         r=min(x[i+1],s[j].xb);
 29         ans+=2LL*(r-x[i])*to;
 30         if(r>s[j].xb-to){
 31             if(x[i]<s[j].xb-to){
 32                 int l=r-(s[j].xb-to);
 33                 ans-=(ll)l*l;
 34             }
 35             else{
 36                 ans-=(ll)(r-x[i])*(r-x[i]);
 37                 int l=x[i]-(s[j].xb-to);
 38                 ans-=2LL*l*(r-x[i]);
 39             }
 40         }
 41     }
 42     th++;
 43     for(i=1;i<=ls;++i){
 44         if(s[i].ty<=th)  u[i]=false;
 45         else{
 46             u[i]=true;
 47             s[i].xb=x[s[i].tx]-(y[th]-y[s[i].y]);
 48         }
 49     }
 50     int k=ls;ls=0;
 51     for(i=1;i<=k;++i){
 52         if(u[i])  s[++ls]=s[i];
 53     }
 54 }
 55 int main(){
 56     freopen("tri.in","r",stdin);
 57     freopen("tri.out","w",stdout);
 58     scanf("%d",&n);
 59     int i,j,k;
 60     for(i=1;i<=n;++i){
 61         scanf("%d%d%d",&tri[i].x,&tri[i].y,&tri[i].m);
 62         x[++lx]=tri[i].x;x[++lx]=tri[i].x+tri[i].m;
 63         y[++ly]=tri[i].y;y[++ly]=tri[i].y+tri[i].m;
 64     }
 65     sort(x+1,x+lx+1);sort(y+1,y+ly+1);
 66     lx=unique(x+1,x+lx+1)-x-1;
 67     ly=unique(y+1,y+ly+1)-y-1;
 68     y[ly+1]=2e9;x[lx+1]=2e9;
 69     for(i=1;i<=n;++i){
 70         tri[i].tx=lower_bound(x+1,x+lx+1,tri[i].x+tri[i].m)-x;
 71         tri[i].ty=lower_bound(y+1,y+ly+1,tri[i].y+tri[i].m)-y;
 72         tri[i].x=lower_bound(x+1,x+lx+1,tri[i].x)-x;
 73         tri[i].y=lower_bound(y+1,y+ly+1,tri[i].y)-y;
 74         tri[i].xb=x[tri[i].tx];
 75     }
 76     sort(tri+1,tri+n+1,cmp);
 77     tri[n+1].y=ly+1;
 78     ls=1;s[ls]=tri[1];th=tri[1].y;s[0].xb=-2e9;
 79     for(i=2;i<=n+1;++i){
 80         while(ls && tri[i].y>th)  work();
 81         if(th<tri[i].y)  th=tri[i].y;
 82         bool found=false;
 83         for(j=1;j<=ls;++j){
 84             if(tri[i].x<s[j].x){
 85                 if(tri[i].xb<=s[j-1].xb)  break ;
 86                 for(k=ls;k>=j;--k)  s[k+1]=s[k];
 87                 s[j]=tri[i];
 88                 int lr=ls+1;ls=j;
 89                 for(k=j+1;k<=lr;++k){
 90                     if(s[k].xb>s[j].xb)  s[++ls]=s[k];
 91                 }
 92                 found=true;
 93             }
 94         }
 95         if(!found && tri[i].xb>s[ls].xb)  s[++ls]=tri[i];
 96     }
 97     if(ans&1){
 98         printf("%lld.5",ans/2);
 99     }
100     else  printf("%lld.0",ans/2);
101     return 0;
102 }
tri.cpp

 

以上是关于2017.09.03校内训练的主要内容,如果未能解决你的问题,请参考以下文章

校内训练2019-11-15跳一跳

校内训练2019-11-15逮虾户

校内训练2019-11-15表演

20171129校内训练

「csp校内训练 2019-10-30」解题报告

三中校内训练净化