20年11月27日的比赛了,一共20题,当时写了十七题rank30,现在拿出来把它写完整理一下吧。
A找一下规律。前三行:第i行输出i-1个空格和V和2*(n-i)-1个空格和V和换行,最后一行输出3个空格和一个V,循环搞定。
#include<bits/stdc++.h> using namespace std; int main() { int n=4; for(int i=1;i<n;i++) { for(int j=1;j<i;j++)cout<<' '; cout<<'V'; for(int j=1;j<=1+2*(n-i-1);j++) cout<<' '; cout<<'V'; cout<<endl; } for(int j=1;j<=n-1;j++) cout<<' '; cout<<'V'; return 0; }
B就读入ab,输出100*b/a的三位小数+百分号,用printf的保留三位小数挺好。(还好不想yyh的那道毒瘤题)
#include<bits/stdc++.h> using namespace std; int main() { long long a,b; cin>>a>>b; double x=100.00*b/a; printf("%.3f%%",x); return 0; }
C就读入mn,如过m%n==0输出YES,否则输出NO。
#include<bits/stdc++.h> using namespace std; long long m,n; int main() { cin>>m>>n; if(m%n==0) cout<<"YES"; else cout<<"NO"; return 0; }
D题可以看做是一道60进制的减法。我就直接sum=(h2-h1)*60+m2-m1得到总的分钟数,那么小时应该是sum/60,分钟数应该是sum%60。想一秒特殊情况:不到一小时和整小时,都挺对的,那就没啥问题了。
#include<bits/stdc++.h> using namespace std; int a,b,c,d; int main() { cin>>a>>b>>c>>d; int sum=d-b+(c-a)*60; cout<<sum/60<<' '<<sum%60; return 0; }
E也是小模拟。本来还想开数组啥的,看一眼数据范围是11~99仅有两位数,if表达式挺好写的,直接开搞。a==b时100块;20块是12、21这样个位对应十位,十位对应个位这样,a/10==b%10&&a%10==b/10;2块是有一个数字相同,a%10==b/10||a%10==b%10||a/10==b/10||a/10==b%10。上面的用if和else if,0块用else即可对应全部情况。
#include<bits/stdc++.h> using namespace std; int a,b; int main() { cin>>a>>b; if(a==b) cout<<100; else if(a%10==b/10&&a/10==b%10) cout<<20; else if(a%10==b/10||a%10==b%10||a/10==b/10||a/10==b%10) cout<<2; else cout<<0; return 0; }
F不想说了。
#include<bits/stdc++.h> using namespace std; int main() { int n; for(cin>>n;n;n--) cout<<"China will win the battle against COVID-19."<<endl; return 0; }
G可以sort得到最高最低分,但是平均分还是要扫一遍,那顺便更新最高分最低分算了,不用sort了。
#include<bits/stdc++.h> using namespace std; int a[10010],maxx,minn,sum; int main() { int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; maxx=minn=a[1]; for(int i=1;i<=n;i++) { maxx=max(maxx,a[i]); minn=min(minn,a[i]); sum+=a[i]; } printf("%.2f %d %d",sum*1.0/n,maxx,minn); return 0; }
H到这儿我想起来了,我是先做的H再做的A,于是可以照搬代码到A。那些先写A的还要推一下公式哈哈哈哈。
#include<bits/stdc++.h> using namespace std; int main() { int n;cin>>n; for(int i=1;i<n;i++) { for(int j=1;j<i;j++)cout<<' '; cout<<'V'; for(int j=1;j<=1+2*(n-i-1);j++) cout<<' '; cout<<'V'<<endl; } for(int j=1;j<=n-1;j++) cout<<' '; cout<<'V'; return 0; }
I用map和数组写都挺好。map写完还要用迭代器,那个我没学会,还是算了。这波啊,这波是空间换时间,如果空间开不下要用nlog(n)sort后扫一遍,写起来也简单。
#include<bits/stdc++.h> using namespace std; int t,sum[10010]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>t; sum[t]++; } for(int i=10000;i;i--) if(sum[i]) cout<<i<<'-'<<sum[i]<<endl; return 0; }
之前的题都是有手就行,下面的题需要一些能力了。
J是前缀和例题。令sum[i]=Σa[1],a[i],那么p和q覆盖的子序列和为sum[q]-sum[p-1],预处理前缀和数组只需sum[i]=sum[i-1]+a[i],由于q可能大于n,于是把sum[n+1]到sum[10000]都赋值为sum[n]。
#include<bits/stdc++.h> using namespace std; int a[1010],sum[10010]; int n,t,l,r; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i],sum[i]=sum[i-1]+a[i]; for(int i=n+1;i<=10000;i++) sum[i]=sum[i-1]; for(cin>>t;t;t--) { cin>>l>>r; cout<<sum[r]-sum[l-1]<<endl; } return 0; }
K是数论题。能同时被n和m整除的最小值是lcm(n,m),所有能同时被n和m整除的值是lcm(n,m)的整数倍。如果k>=lcm,把k减去k%lcm就是小于等于k的最大lcm的倍数,即为所求;如果k<lcm,那么不存在答案。
#include<bits/stdc++.h> using namespace std; long long gcd(long long a,long long b) { return b==0?a:gcd(b,a%b); } int main() { long long n,m,k; cin>>m>>n>>k; long long lcm=m/gcd(m,n)*n; if(k<lcm) cout<<-1; else cout<<k-k%lcm; return 0; }
L是一道高中数学题。问单词学错的种类,考虑求出所有的字母排列的方案数后-1即可。所有字母的排列方案是单词长度的阶乘/每个字母出现的次数的阶乘,很好写。
#include<bits/stdc++.h> using namespace std; int sum[300]; string s; int fac(int x) { int ans=1; while(x) ans=ans*x,x--; return ans; } int main() { cin>>s; for(int i=0;i<s.size();i++) sum[s[i]]++; int ans=fac(s.size()); for(int i='A';i<='Z';i++) ans=ans/fac(sum[i]); cout<<ans-1; return 0; }
M题要求数组元素的总和的方案数。注意到数组元素的总和的最小值是minn*(n-1)+maxx,最大值是maxx*(n-1)+minn,那么答案就是最大值减最小值+1=maxx*n-minn*n-2*(maxx-minn)+1。
#include<bits/stdc++.h> using namespace std; long long n,minn,maxx; int main() { scanf("%lld%lld%lld",&n,&minn,&maxx); cout<<maxx*n-minn*n-2*(maxx-minn)+1; return 0; }
N问闭区间1到n有多少个因子个数为3的数。首先1不是,大于1的数x至少有两个因子1和x它自己。要想满足因子个数是3,需要再来一个因子刚好是根号x。于是问题转化成了求1到根号n中的质数的个数,这些质数的平方都是有趣的数。求质数需要根号n,那么复杂度是根号n乘根号根号n=10^9,差不多能过。
#include<bits/stdc++.h> using namespace std; bool ask(long long x) { long long t=sqrt(x*1.0); for(int i=2;i<=t;i++) if(x%i==0) return 0; return 1; } int main() { int sum=0; long long n; cin>>n; for(long long i=2;i*i<=n;i++) if(ask(i)) sum++; cout<<sum; return 0; }
O题经典找不同。一般的题是给一个天平,用二分的方法。但是这道题直接给了一个能称任意重量的电子秤,直接第i堆拿出i个称重,本应是(1+n)*n/2g重,用实际的质量减它可以得到是那一堆硬币重量为2g,所以只需要分两种情况:1和大于1,答案分别是0和1。
#include<bits/stdc++.h> using namespace std; int main() { long long n;cin>>n; cout<<(n==1?0:1); return 0; }
P给的N首先要能表示成2的正整数次幂的和,表明奇数必然不行了。考虑用lowbit得到N二进制里的1的数量sum,然后不能直接拿着sum==3判断答案,比如8,sum=1但是可以表示成4+2+2。这提醒我们大于等于8的数们即使sum=1也可以,这时N为2^k,只需要拆分成N/2+N/4+N/4。大于6的数sum=2也可以,这时N=2^m+2^n,m>n,只需要拆分成2^(m-1)+2^(m-1)+2^n即可。sum=3当然可以了,sum>3的不行,不存在sum=0的正整数。
#include<bits/stdc++.h> using namespace std; int lowbit(int n) { return n&(-n); } int main() { int n,sum=0,t; cin>>n; if(n%2==1) { cout<<"NO"; return 0; } t=n; while(n) { n=n-lowbit(n); sum++; } if(t>=8&&sum==1||t>=6&&sum==2||sum==3) cout<<"YES"; else cout<<"NO"; return 0; }
Q题是个结论题:1/n是有限小数当且仅当n的质因子只有2和5。这是因为1和任意有限小数除以2,5都是有限小数,除以其他质数都是无限小数。于是把输入进来的n一直除以2和5,看看是不是剩下个1即可。
#include<bits/stdc++.h> using namespace std; int main() { int T,n; for(cin>>T;T;T--) { cin>>n; while(n%5==0) n=n/5; while(n%2==0) n=n/2; if(n==1) cout<<"YES"; else cout<<"NO"; cout<<endl; } return 0; }
R题博弈论我老不会了。用f[n][k]记录第k轮剩n个石子的后手输赢,为1时后手胜,为-1时后手输。那么
f[n][k]=1 <=>对任意i存在j使得f[n-i-j][k+1]=1 f[n][k]=-1<=>存在i对任意j使得f[n-i-j][k+1]=-1
于是可以写个记忆化搜索找规律:
int dfs(int n,int k) { //cout<<n<<' '<<k<<endl; if(f[n][k]) return f[n][k]; if(n==0) { f[n][k]=1; return 1; } if(k>=n) { f[n][k]=-1; return -1; } int flag; for(int i=1;i<=k;i++) { flag=1; for(int j=1;j<=k;j++) { if(n-i-j<0) break; if(dfs(n-i-j,k+1)==1) { flag=-1; break; } } if(flag==1) { f[n][k]=-1; return -1; } } f[n][k]=1; return 1; }
通过仔细观察大胆猜测可以得出,n=k*(k+1)/2时先手胜,否则先手输。于是我写了一个很笨的判断,复杂度TlogT+根号N。
#include<bits/stdc++.h> using namespace std; struct node { int x,i,ans; }o[1010]; bool m1(node a,node b) { return a.x<b.x; } bool m2(node a,node b) { return a.i<b.i; } int main() { int T;cin>>T; for(int i=1;i<=T;i++) cin>>o[i].x,o[i].i=i; sort(o+1,o+1+T,m1); for(int i=1,j=1;i*(i+1)/2-1<=o[T].x;i++) { while(j<=T&&o[j].x<=i*(i+1)/2-1) { if(o[j].x==i*(i+1)/2-1) o[j].ans=1; j++; } } sort(o+1,o+1+T,m2); for(int i=1;i<=T;i++) if(o[i].ans==1) cout<<"YES"<<endl; else cout<<"NO"<<endl; return 0; }