涵盖知识点:贪心、简单几何、找规律etc.
比赛链接:
https://codeforces.com/contest/1300
福利场因为某些NT原因没捞到分血亏。。。
A:Non-zero
题意:每次可以对一个元素+1,问你最少几次操作使所有元素的和与积不为0.
题解:所有为0的数字先+1,若加完后的数字总和为0,再+1.
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int t; 6 cin>>t; 7 while(t--){ 8 int k; 9 cin>>k; 10 int sum=0,cnt=0; 11 while(k--){ 12 int a; 13 cin>>a; 14 sum+=a; 15 if(a==0)cnt++; 16 } 17 int res=cnt; 18 if(sum+cnt==0){ 19 res++; 20 } 21 cout<<res<<" "; 22 } 23 return 0; 24 }
B:Assigning to Classes
题意:将2n个学生分为两组奇数个人,要求两组的中位数差值最小。
题解:2n个人从小到大排序,中间两个人编号减一下即可。
证明:官方题解证明方式,懒得写。。
AC代码(第一发数组没开两倍RE了。。。):
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int num[2*maxn]; 5 int main(){ 6 int t; 7 cin>>t; 8 while(t--){ 9 int n; 10 cin>>n; 11 for(int i=0;i<2*n;i++){ 12 cin>>num[i]; 13 } 14 sort(num,num+2*n); 15 cout<<num[n]-num[n-1]<<" "; 16 } 17 return 0; 18 }
C:Anu Has a Function
题意:给定n个数字,问你怎么排列可以使得n次计算(x|y)-y最后的答案最大。(每次计算后的答案当作下一次的x)。
题解:对于一个二进制位而言,只有x为1,y为0的时候最后答案才为1.所以我们只需要在n个数字中找到某一位有且只有一个1的数字的最大值。1e9范围内直接从30开始递减。复杂度最坏3e6.(然而这题出锅了。。我把最大值记录下来想要减少一些循环次数然后挂在了全0的数据上。。当时还在想为什么会TLE。。原来全0记录完cnt就变-1了就卡了死循环。。然而并没有意识到这一点于是就一直在那里想优化结果就卡了一个小时。。最后底分才过。。然后这场就白给了。。。)
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int num[2*maxn]; 5 int main(){ 6 int n; 7 scanf("%d",&n); 8 int ma=0; 9 for(int i=0;i<n;i++) { 10 scanf("%d",&num[i]); 11 if(ma<num[i]) 12 ma=num[i]; 13 } 14 int cnt=30; 15 //cout<<ma<<endl<<cnt<<endl; 16 int res=0,resi; 17 while(cnt>=0){ 18 int i,flag=0; 19 for(i=0;i<n;i++){ 20 if(num[i]&(1<<cnt)){ 21 //cout<<"666"<<endl; 22 flag++; 23 res=num[i]; 24 resi=i; 25 } 26 if(flag>=2){ 27 break; 28 } 29 } 30 if(flag==1) 31 break; 32 cnt--; 33 } 34 cout<<res; 35 for(int i=0;i<n;i++){ 36 if(i==resi)continue; 37 else printf(" %d",num[i]); 38 } 39 cout<<" "; 40 return 0; 41 }
D:Aerodynamic
题意:给你n个逆时针排序的点组成n凸多边形,将这个多边形移动(x,y)向量使得原点在这个多边形内,这些向量组成一个新的多边形,问你这两个多边形是否相似。
题解:看题意图其实就是多边形的边上每一个点绕着原点画一圈看看,发现只要是偶数条边并且对边分别平行就行了。或者偶数边中心对称也可以。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=3e5+10; 4 typedef long long ll; 5 ll x[maxn],xx[maxn],y[maxn],yy[maxn]; 6 int main(){ 7 int n; 8 cin>>n; 9 for(int i=0;i<n;i++){ 10 cin>>x[i]>>y[i]; 11 } 12 if(n&1){cout<<"NO ";return 0;} 13 bool flag=true; 14 for(int i=0;i<n;i++){ 15 xx[i]=x[(i+1)%n]-x[i]; 16 yy[i]=y[(i+1)%n]-y[i]; 17 } 18 n>>=1; 19 for(int i=0;i<n;i++){ 20 int f1,f2,f3,f4; 21 f1=f2=f3=f4=0; 22 if(xx[i]>0)f1=1; 23 if(yy[i]>0)f2=1; 24 if(xx[i]<0)f1=-1; 25 if(yy[i]<0)f2=-1; 26 if(xx[i+n]>0)f3=1; 27 if(yy[i+n]>0)f4=1; 28 if(xx[i+n]<0)f3=-1; 29 if(yy[i+n]<0)f4=-1; 30 if(f1*f2!=f3*f4||abs(xx[i])!=abs(xx[i+n])||abs(yy[i])!=abs(yy[i+n])){ 31 flag=false; 32 break; 33 } 34 } 35 if(flag)cout<<"YES "; 36 else cout<<"NO "; 37 return 0; 38 }
E:Water Balance
题意:给定一个序列,每次可以将一个序列的某一个区间内的所有值变为该区间的平均值,可以进行任意次操作。求操作后的最小字典序区间。
题解:贪心,从前往后,记录前缀和和区间长度。若遇到后面的某一个值比当前区间的平均值要小,将下一个值加入当前区间。否则开始从下一个值开始重新开始记录前缀和和区间长度。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e6+10; 4 typedef long long ll; 5 ll p[maxn],q[maxn],a[maxn]; 6 int main(){ 7 int n; 8 cin>>n; 9 for(int i=1;i<=n;i++){ 10 cin>>a[i]; 11 } 12 ll pre=0,tmp=0,cnt=0; 13 for(int i=1;i<=n;i++){ 14 pre=a[i],cnt=1; 15 while(tmp&&p[tmp]*cnt>=pre*q[tmp])pre+=p[tmp],cnt+=q[tmp--]; 16 p[++tmp]=pre; 17 q[tmp]=cnt; 18 } 19 // for(int i=1;i<=n;i++)cout<<p[i]<<" "<<q[i]<<endl; 20 for(int i=1;i<=tmp;i++){ 21 for(int j=1;j<=q[i];j++){ 22 printf("%.9lf ",(double)p[i]/q[i]); 23 } 24 } 25 return 0; 26 }
总结:
大半夜的脑子总有点不太清醒。。C题出大锅导致DE看都没看。。心态爆炸QAQ