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 }
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 }
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 }
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 }
以上是关于2017.09.03校内训练的主要内容,如果未能解决你的问题,请参考以下文章