兰州大学第一届『飞马杯』程序设计竞赛(同步赛)
A.比赛新机制
题意:每道题目的罚时 s与比赛已经开始的时间(按分钟计) a 以及该题错误的提交次数(不包括编译错误) b 有关,即 s=a+b×20;Alice所有的题目提交一次便成功,有n 道题目。它可以从任意一道题目开始正序或者逆序完成,求最小的罚时数。
题解:对于正序,如果顺序为a1,a2,a3,......,an, 那么s1=n*a1+(n-1)*a2+(n-2)*a3+.......+2an-1+an;如果顺序为a2,a3,......,an,a1,那么s2=n*a2+(n-1)a3+......+2an+a1,s1-s2=(n-1)*a1-a2-a3-......-an=n*a1-sum;得si+1=si+sum-n*ai
对于逆序,如果顺序为an,an-1,......a3, a2, a1,sn=n*an+(n-1)an-1+......+a1;如果顺序为an-1,......a3, a2, a1,an,得sn-1=n*an-1+(n-1)an-2+***+2a1+an;si+1-si=n*ai+1-sum
每次递推更新最小值
反思:在数组得类型和声明位置错了好几次,大数组要定义在main函数外!同一代码,一会超时一会不超时的,还不知道为啥。
#include<bits/stdc++.h> using namespace std; #define MAXN 500010 #define NAF 1e18 typedef long long ll; ll a[MAXN]; //用int错,放main里错,找了好几遍!! int main(){ ios::sync_with_stdio(false); int t; cin>>t; int n; while(t--){ ll sum=0,minn=NAF,ans=0,reans=0; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; sum+=a[i]; ans+=(n-i+1)*a[i]; reans+=i*a[i]; } minn=min(reans,ans); //正序 for(int i=1;i<=n;i++){ ans=ans+sum-n*a[i]; minn=min(ans,minn); } //逆序 for(int i=n;i>=1;i--){ reans=reans-n*a[i]+sum; minn=min(minn,reans); } cout<<minn<<endl; } return 0; }
C.生命的游戏
题意:

题解:数据范围小,暴力模拟。
#include<bits/stdc++.h> using namespace std; #define MAXN 105 int s[MAXN][MAXN],s1[MAXN][MAXN],s2[MAXN][MAXN],n; bool check(int a[][105],int b[][105]){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(a[i][j]!=b[i][j]){ return false; } } } return true; } int sum(int x,int y){ int x1,x2,y1,y2,cnt=0; x1=x-1,y1=y-1,x2=x+1,y2=y+1; if(x==1) x1=n; if(y==1) y1=n; if(x==n) x2=1; if(y==n) y2=1; if(s1[x1][y]==1) cnt++; if(s1[x1][y1]==1) cnt++; if(s1[x1][y2]==1) cnt++; if(s1[x][y1]==1) cnt++; if(s1[x][y2]==1) cnt++; if(s1[x2][y1]==1) cnt++; if(s1[x2][y]==1) cnt++; if(s1[x2][y2]==1) cnt++; return cnt; } int main(){ int t; cin>>t; int k; while(t--){ int flag=0,cnt=0; cin>>n>>k; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>s[i][j]; s1[i][j]=s[i][j]; s2[i][j]=s[i][j]; } } while(k--){ cnt++; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(sum(i,j)==3){ s2[i][j]=1; }else if(sum(i,j)<2||sum(i,j)>3){ s2[i][j]=0; }else{ s2[i][j]=s1[i][j]; } } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ s1[i][j]=s2[i][j]; } } if(check(s,s2)){ flag=1; break; } } if(flag==1){ cout<<"YES"<<endl; cout<<cnt<<endl; }else{ cout<<"NO"<<endl; } } return 0; }
F.飞马分隔符
题意:子序列为原字符串中删去若干字符,剩余字符相对位置不变形成的序列。需要将这个字符串 s按顺序划分为若干部分s1,s2,…,sk,且 s1+s2+⋯+sk=s(+ 表示字符串的连接),使得每一部分都不包含子序列FeiMa。而每次划分都需要一个“分隔符”,求至少需要多少分隔符。
题解:有多少子序列FeiMa就需要多少分隔符。从头到尾遍历,每次遇到字符 a ,判断前面是否顺次出现过一组 F、e、i、M,若出现过,则在此处分隔,更新答案,并清空记录。
#include<bits/stdc++.h> using namespace std; int main(){ int t; cin>>t; int n,temp; string s,str="FeiMa"; while(t--){ int cnt=0; cin>>n; cin>>s; int flag=0; for(int i=0;i<n;i++){ if(s[i]=='F'&&flag==0){ flag+=1; }else if(s[i]=='e'&&flag==1){ flag+=1; }else if(s[i]=='i'&&flag==2){ flag+=1; }else if(s[i]=='M'&&flag==3){ flag+=1; }else if(s[i]=='a'&&flag==4){ cnt++; flag=0; } } cout<<cnt<<endl; } return 0; }
H.温暖的力量
题意:给一个数,求他最多能被分成几个素数。素数的个数大于1.无解输出-1,有解输出答案
题解:把这个数全部分成2和3.
#include<bits/stdc++.h> using namespace std; int main(){ int t; cin>>t; int s; while(t--){ cin>>s; if(s<=3){ cout<<-1<<endl; }else{ cout<<s/2<<endl; } } return 0; }
J.翻滚吧硬币

题意:任取两枚硬币固定在二维平面上,并让它们恰好相切,用第三枚硬币沿着它们形成的边界进行翻滚,即时刻保证与至少一枚已固定的硬币相切。这样这枚运动的硬币在翻滚了一定的圈数之后,一定会回到原点,即恰好绕了一周。有三种情况,AB固定C运动;AC固定B运动;BC固定A运动。
题解:

#include<bits/stdc++.h> using namespace std; #define pi 3.1415926535897 int main(){ ios::sync_with_stdio(false); int t; cin>>t; double r[3]; double a,b,t1,t2,t3,s; while(t--){ cin>>r[0]>>r[1]>>r[2]; sort(r,r+3); t1=r[2]+r[0]; t2=r[0]+r[1]; t3=r[2]+r[1]; a=acos((t1*t1+t2*t2-t3*t3)/(2*t1*t2)); b=acos((t3*t3+t2*t2-t1*t1)/(2*t3*t2)); s=2*(pi-a)*t1+2*(pi-b)*t3; printf("%.10f\n",s/(2*pi*r[2])); } return 0; }

浙公网安备 33010602011771号