2017.09.06校内训练
T1:切糕
题解:根据相似三角形的性质,我们可以推出:横切:枚举每一份,答案为(b-b*√(i/n))(1<=i<=n-1).竖切分两类:一类是切成偶数块,这样中间要切一刀,左边的答案为(a/2*√(i/(n/2)))右边答案为a-左边的答案;另一类切成奇数块:中间不需要切,左右答案与前面一样。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 int n,a,b,c; 9 double s,eps=1e-15; 10 double ans; 11 double ll[1010]; 12 double sqr(double t){ 13 double l=t,r=1,mid; 14 while(l+eps<r){ 15 mid=(l+r)/2.0; 16 if(mid*mid<t) l=mid; 17 else r=mid; 18 } 19 return r; 20 } 21 int main(){ 22 freopen("cut.in","r",stdin); 23 freopen("cut.out","w",stdout); 24 scanf("%d%d%d%d",&n,&a,&b,&c); 25 memset(ll,0,sizeof(ll)); 26 int i,j,k; 27 s=a*b/2.0; 28 if(c==1){ 29 if(n%2==0){ 30 int cnt=0,qwq; 31 for(i=1;i<=n/2-1;++i){ 32 double ha=2.0*(double)i/(double)n; 33 ans=sqr(ha); 34 ans=ans*(double)a/2.0; 35 ll[++cnt]=ans; 36 } 37 qwq=cnt; 38 ll[++cnt]=(double)a/2.0; 39 for(i=qwq;i>=1;--i) ll[++cnt]=a-ll[i]; 40 for(i=1;i<=cnt;++i){ 41 printf("%f\n",ll[i]); 42 } 43 return 0; 44 } 45 if(n%2!=0){ 46 int cnt=0,qwq; 47 for(i=1;i<=n/2;++i){ 48 double ha=2.0*(double)i/(double)n; 49 ans=sqr(ha); 50 ans=ans*(double)a/2.0; 51 ll[++cnt]=ans; 52 } 53 qwq=cnt; 54 for(i=qwq;i>=1;--i) ll[++cnt]=a-ll[i]; 55 for(i=1;i<=cnt;++i){ 56 printf("%f\n",ll[i]); 57 } 58 return 0; 59 } 60 } 61 if(c==0){ 62 int cnt=0; 63 for(i=1;i<=n-1;++i){ 64 double ha=(double)i/(double)n; 65 ans=sqr(ha); 66 ans=ans*(double)b; 67 ll[++cnt]=(double)b-ans; 68 } 69 for(i=n-1;i>=1;--i) printf("%lf\n",ll[i]); 70 return 0; 71 } 72 return 0; 73 }
T2:采购
题解:考虑二分答案,check部分对每个物品实际需要用的价格sort,从小到大取。需要开long long。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 #define ll long long 10 using namespace std; 11 int n,m,l,r,mid,ans; 12 ll a[100010],b[100010],sum[100010]; 13 bool check(int mid){ 14 ll kk=0; 15 int i; 16 for(i=1;i<=n;++i){ 17 sum[i]=a[i]+(mid-1)*b[i]; 18 } 19 sort(sum+1,sum+n+1); 20 for(i=1;i<=mid;++i){ 21 kk+=sum[i]; 22 if(kk>m) return false; 23 } 24 return true; 25 } 26 int main(){ 27 freopen("buy.in","r",stdin); 28 freopen("buy.out","w",stdout); 29 int i,j; 30 scanf("%d%d",&n,&m); 31 for(i=1;i<=n;++i){ 32 scanf("%d%d",&a[i],&b[i]); 33 } 34 l=0;r=n; 35 while(l+1<r){ 36 mid=(l+r)>>1; 37 if(check(mid)==true) l=mid; 38 else r=mid-1; 39 } 40 if(check(r)==true) ans=r; 41 else ans=l; 42 printf("%d\n",ans); 43 }
T3:能量
题解:我们可以通过求异或和,得出每一个数。因此我们记前k个数的异或和。以每一段的异或和为边权,该段起点和终点分别为定点,跑最小生成树即可(如果用kruskal只可以取得70分,prim不使用堆的那一种是100分)。
代码:
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 ll d[10010],u[10010]; 10 ll a[10010]; 11 int to[10010]; 12 ll ans=0; 13 int n,mn; 14 int main(){ 15 freopen("power.in","r",stdin); 16 freopen("power.out","w",stdout); 17 int i,j,x; 18 scanf("%d",&n); 19 for(i=1;i<=n;++i){ 20 scanf("%d",&x);d[i]=a[i]=a[i-1]^x; 21 } 22 for(i=1;i<=n;++i){ 23 mn=0; 24 for(j=1;j<=n;++j){ 25 if(!u[j] && (!mn || d[j]<d[mn])) mn=j; 26 } 27 ans+=d[mn];u[mn]=1; 28 for(j=1;j<=n;++j){ 29 d[j]=min(d[j],a[j]^a[mn]); 30 } 31 } 32 printf("%lld",ans); 33 return 0; 34 }