1. 程式人生 > >2017.09.03校內訓練

2017.09.03校內訓練

-a 模板 sca aps 最優解 有一種 es2017 這一 分享

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校內訓練