SICNU 2018 Summer Training #2
Posted maybe96
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SICNU 2018 Summer Training #2相关的知识,希望对你有一定的参考价值。
这场比赛感觉起来还是比较基础的吧,一半多的题目应该都是可以做的,但是还是太菜了,只做了5题。。也是因为时间比较赶有几题过题少的都没看题
b题在比赛的时候没做出来,wa了几次就转其他题目了,思路应该比较常规,就是纸上模拟找下规律,因为数据比较大所以也不能直接模拟,规律应该就是如果第一行可以放满,就每个人都有一个,然后分奇偶
如果是偶数行数就前面n-1个可以得到糖果,否则就是后面n-1个可以得到糖果,然后其实就是中间的不影响,只是第一个和最后一个是减半的,而且根据奇偶要-1或者不变,然后就模拟最后一行就好了,然后特判一下没排满第一行的情况就行了。
c题题意一开始没读懂,以为是n&(n-1)的情况,然后wa了,后面Google翻译了一下就是二进制翻转,找小于他本身的最大的那个数,其实就是找1了,如果找到了第一个1,就翻转就行了,最后输出1的位数
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <set> #include <map> #include <string> using namespace std; int main() { int t; int n,m; int s[10000]; cin>>t; while(t--){ cin>>n; int a=0; m=0; while(n>0){ s[a++]=n%2; n/=2; } for(int i=0;i<a;i++){ m++; if(s[i]==1) break; } cout<<m<<endl; } return 0; }
然后是D题,实质上就是找规律,如果n==m 就很好办,正方形经过所以块的边就是n*(n+1)/2,否则就必须分n和m的奇偶情况
如果奇偶性相同就是跟相同的情况相似,只不过有两种情况就是取两种情况的最小m*(n+1)/2
如果奇偶性不同,就需要对折,然后与直接的m*(n+1)/2,进行比较
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <set> #include <map> #include <cstring> using namespace std; int cmp(int x,int y){ return x>y; } int main() { int t; long long n,m; cin>>t; while(t--){ cin>>n>>m; if(n==m){ cout<<n*(n+1)/2<<endl; } else{ long long s; if(n%2==0&&m%2==0) s=min(n*(m+1)/2,m*(n+1)/2); else if(n%2==1&&m%2==0) s=min(m*(n/2+1)/2+(m/2+1)*(n/2),m*(n+1)/2); else if(n%2==0&&m%2==1) s=min((m/2+1)*n/2+(m/2)*(n/2+1),n*(m+1)/2); else s=min((n+1)*m/2,(m+1)*n/2); cout<<s<<endl; } } return 0; }
f题思路挺好想的,就是贪心,先用map存,排序从大到小进行判断,每个数从1到平方根判断是否能被整除,如果能,再判断两个因数是否在map里,如果小因数在,就直接break,如果大因数在就需要继续判断是否还有比这个因数小的存在,思路和实现没太大的问题,主要是这题有点卡时间,一开始一直tle,不断修改,也不知道哪里有问题,后来发现使用cin和cout进行输入和输出是不行的,要使用printf或者scanf,或者取消流同步,然后就是在两个因数的判断上可能存在一些易错点
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <set> #include <map> #include <cstring> using namespace std; int cmp(int x,int y){ return x>y; } int main() { int t; scanf("%d",&t); int n,m; int num[100005]; map<int,int>s; while(t--){ long long sum=0; s.clear(); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&num[i]); s[num[i]]=1; } sort(num,num+n,cmp); for(int i=0;i<n;i++){ int t=0; int ss=0; for(int j=1;j<=sqrt(num[i]);j++){ if(num[i]%j==0){ if(s[j]!=0){ num[i]=j; t=0; break; } else if(s[num[i]/j]){ ss=num[i]/j; t=1; } } } if(t==1) num[i]=ss; sum+=num[i]; } printf("%lld ",sum); } return 0; }
h题应该是个签到题,挺简单的,O(N)复杂度找前后两数和的最大值
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <set> #include <map> #include <string> using namespace std; int main() { int n,m; int num[2005]; int t; cin>>t; while(t--){ cin>>n; int maxn=-1; for(int i=0;i<2*n;i++) cin>>num[i]; for(int i=0;i<n;i++){ maxn=max(maxn,num[i]+num[2*n-i-1]); } cout<<maxn<<endl; } return 0; }
i题应该也是签到题
大意就是给一个数,然后告诉需要划分几份,找最平均的划分(最大值与最小值的差最小)
其实就是两种情况,一直是只有n/m的情况,一种就是有n/m和n/m+1的情况
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <set> #include <map> #include <string> using namespace std; int main() { int n,m; int t; cin>>t; while(t--){ cin>>n>>m; if(m>n){ cout<<-1<<endl; continue; } if(m==n){ for(int i=0;i<n;i++){ if(i!=0) cout<<‘ ‘; cout<<1; } } else{ if(n%m==0){ for(int i=0;i<m;i++){ if(i!=0) cout<<‘ ‘; cout<<n/m; } } else { int t=n/m; int s=n-t*m; for(int i=0;i<m-s;i++){ if(i!=0) cout<<‘ ‘; cout<<t; } for(int i=0;i<s;i++) cout<<‘ ‘<<t+1; } } cout<<endl; } return 0; }
以上是关于SICNU 2018 Summer Training #2的主要内容,如果未能解决你的问题,请参考以下文章
MYGE 2018 SPRING/SUMMER COLLECTION
集训实录2018_XDU_ACM_SUMMER_TRAINING
Deep Learning and Reinforcement Learning Summer School 2018
2018-2019 Summer Petrozavodsk Camp, Oleksandr Kulkov Contest 2解题报告