廣東工業大學2018新生杯決賽
題出的好!難度適中,覆蓋知識點廣,題目又著切合實際的背景,解法比較自然。給出題人點贊 !
然而我太菜了,只會8/13,差不多一半不會
A: 文遠知行β
題目加粗,n個時刻速度均大於0.
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int t,n; int main() { cin>>t; while(t--) { bool ok=1; int x; cin>>n; for(int i=1;i<=n;i++){cin>>x;if(!x)ok=0;} if(ok)puts("WeRide.ai"); else puts("Transform Mobility With Autonomous Driving"); } return 0; }
B: 學姐是野兔先輩β
原來是0不變,原來非0一半概率x-lowbit(x),一半概率x+lowbit(x),期望還是x,因此不管怎麼操作答案就是原數列的值。
所以用字首和就出來了。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int t,n,m,a[100005]; char type[105],name[105]; int l,r,num; int sum[100005]; int main() { //freopen("input.in","r",stdin); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); sum[1]=a[1]; for(int i=2;i<=n;i++)sum[i]=sum[i-1]+a[i]; for(int i=1;i<=m;i++) { scanf("%d%d%d",&num,&l,&r); if(num==2) { printf("%d\n",sum[r]-sum[l-1]); } } } return 0; }
C: 名為青春的悖論β
以一個點為基準點,用一個數組s[]記錄每個點與基準點的距離,開個桶have[x]==0or1記錄是否存在一個點與基準點距離為x,要形成矩形,就是選兩條直徑,對應的4個點一定能圍成矩形,設tot為直徑條數,矩形個數為c(tot,2)。
要求出tot,只需在從基準點開始的半圓內列舉每一個點,看另半個圓裡是否有點與此點距離為半圓周長。如果圓周長為奇數,那麼一定不存在兩點位於一條直徑上,因為點間距離都是整數。
複雜度o(n)
#include<iostream> #include<cstring> using namespace std; int n,s[305],cir; bool have[4505]; int main() { //freopen("input.in","r",stdin); while(cin>>n) { memset(have,0,sizeof(have)); for(int i=1;i<=n;i++) { cin>>s[i]; s[i]+=s[i-1]; have[s[i]]=1; } cir=s[n]/2; int tot=(have[cir]); for(int i=1;s[i]<cir;i++)if(have[s[i]+cir])tot++; if(s[n]&1)cout<<0<<endl; else cout<<tot*(tot-1)/2<<endl; } return 0; }
D: 明日會吹明日的風?β
用gets()每次讀入一行,判斷第一個字元就可以知道是哪種型別了。不知道為什麼開始用scanf+strcmp一直wa,感覺情況都處理到了啊。。最後一小時換成gets()馬上就過了。。
//時隔一週,終於找到了錯,原來在寫strcmp時寫的strcmp(type,"double "),double後面多了個空格。。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int t,n;
char name[100005];
int main()
{
//freopen("input.in","r",stdin);
scanf("%d",&t);
while(t--)
{
int ans=0;
scanf("%d",&n);
getchar();
for(int i=1;i<=n;i++)
{
fgets(name,10000,stdin);
if(name[0]=='i')ans+=4;
else if(name[0]=='f')ans+=4;
else if(name[0]=='d')ans+=8;
else if(name[0]=='l')ans+=8;
else if(name[0]=='c')ans+=1;
else if(name[0]=='b')ans+=1;
}
if(ans%1024==0)printf("%d\n",ans/1024);
else printf("%d\n",(ans/1024+1));
}
return 0;
}
E: 把所有的謊言獻給你β
把一個自然數劃分為若干個不重複的數的和,使這些數之積最大。
首先,如果是把x劃分為n份,可以每份相等,則乘積最大時每份都是x/n。(a+1)(a-1)=a*a-1,可以這麼不準確地理解一下。自己對數字很不敏感,開始時認為乘積最大對應的每份都不相等,實際上是相等的。
劃分的每份相等,那麼劃分多少次呢?如果不要求每份為整數,答案是每份為e,劃分為x/e份。
推導見圖:把k劃分為n份
那麼,如果是把一個自然數劃分為若干個可重複的數的和,使這些數之積最大,只需根據x%3,儘可能多劃分出3,剩下的劃分為2.
把一個自然數劃分為若干個不重複的數的和,使這些數之積最大。對於這個問題,詳盡的思路參考這篇bloghttps://blog.csdn.net/u012879957/article/details/82382460
大體意思就是依次拆成2,3,4,5......k剩下的不能k+1的放到2~k之上。
#include<iostream>
using namespace std;
int main()
{
int t,n;
cin>>t;
while(t--)
{
long long ans=1;
cin>>n;
int k=2;
while((2+k+1)*(k-1+1)/2<=n)k++;
int t=k-(n-(2+k)*(k-1)/2)+1;
for(int i=2;i<=k;i++)ans*=(i<t?i:i+1);
if(t==1)ans=ans/(k+1)*(k+2);
if(n==1)cout<<"1 1\n";
else if(n==2)cout<<"2 2\n";
else cout<<n-1<<" "<<ans<<"\n";
}
return 0;
}
F: 那天的延長線在今天β
模擬
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int t,n,a[10005];
int main()
{
//freopen("input.in","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int ans=1;
int pos=2;
while(pos<=n)
{
int i;
for(i=pos;i<=n;i++)
{
if(a[i]!=a[i-1]+1)break;
}
ans=max(ans,i-pos+1);
pos=i;
pos++;
}
printf("%d\n",ans);
}
return 0;
}
G: 活在無盡夢境的後續 β
圍成半圓
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define pi (acos(-1))
int t,n,m,a[100005];
char type[105],name[105];
int l,r,num;
int sum[100005];
int main()
{
//freopen("input.in","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%f\n",n*n/pi/2);
}
return 0;
}
H: 以行走般的速度β
參考樣例,自己手推,原數字與另一個數字互相正負轉化4次後,回到原數字。因為轉換後就不能再使用這個轉換方式了,以n=6為例,2-4是4*2=8,2-6是4*3=12,3-6是4*2=8,其餘2~6每個數字本身正負轉換一次答案是33。可以假設每個數轉化為它的所有因數一次,它的因數不轉化為它。這樣就是4-2,6-2,6-3,其餘正負轉化。
用這樣的思路預處理就好了。
#include<cstdio>
using namespace std;
long long n,a[100005];
int main()
{
for(int i=2;i<=100000;i++)a[i]=1;
for(int i=2;i<=50000;i++)
{
for(int j=i*2;j<=100000;j+=i)
{
a[j]+=4*j/i;
}
}
for(int i=3;i<=100000;i++)a[i]+=a[i-1];
while(~scanf("%lld",&n))printf("%lld\n",a[n]);
return 0;
}
I: 灰暗而空虛的景色β
三個要點:
1.假設有3個數:i<j<k,題目從前往後是jik,則先處理j,後處理i,和不處理j是一樣的,處理完i,處理k,i~k由第二次操作確定,k~n由第三次操作確定。故從後往前看,只有當前處理的位置比後面處理的位置靠左邊才做處理。
2. 1^2+2^2+3^2+......+n^2==n*(n+1)*(2*n+1)/6
3.x/y%k==x%(y*k)/y
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int t,n,q;
int query[100005];
long long ans;
long long fac(long long n)
{
long long ret=1;
ret=ret*n%(6*123456789);
ret=ret*(n+1)%(6*123456789);
ret=ret*(2*n+1)%(6*123456789);
ret/=6;
return ret;
}
int main()
{
// freopen("input.in","r",stdin);
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d%d",&n,&q);
for(int i=1;i<=q;i++)scanf("%d",&query[i]);
long long last=n+1,pos=q,num=(1<<30);
while(pos>=1)
{
if(query[pos]>=num)pos--;
else
{
ans+=fac(last-query[pos]);
ans%=123456789;
last=query[pos];
num=query[pos];
pos--;
}
}
printf("%lld\n",ans);
}
return 0;
}
J: 溫柔的手彼此相系β
將電話號碼標準化為數字或者字串,用map<string,int>或map<int,int >來存,最後遍歷時因為map本身就是按照key排序的,因此直接遍歷一遍map就好了。比賽時忘了這個性質,用了好多東西,程式碼又臭又長。
自己是標準化為數字,這樣就要注意電話號碼第一位或者第四位為0時,輸出要補0,直接輸出的話就空了一位,好在最後一個小時終於看出來了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<cctype>
#include<map>
using namespace std;
int n,cnt[100005];
vector<int> v,ans;
map<int,int> vis;
int num[26]={2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,0,7,7,8,8,8,9,9,9,0};
char s[1005];
int to[100005];
bool cmp(int x,int y)
{
return ans[x]<ans[y];
}
int main()
{
//freopen("input.in","r",stdin);
while(scanf("%d",&n)!=EOF)
{
vis.clear();
ans.clear();
memset(cnt,0,sizeof(cnt));
while(n--)
{
v.clear();
scanf("%s",s);
int len=strlen(s);
for(int i=0;i<len;i++)if(s[i]!='-')
{
if(isdigit(s[i]))v.push_back(s[i]-'0');
else v.push_back(num[s[i]-'A']);
}
int number=0;
for(int i=0;i<7;i++)number=number*10+v[i];
if(vis.count(number))
{
for(int i=0;;i++)
{
if(ans[i]==number)
{
cnt[i]++;
break;
}
}
}
else
{
ans.push_back(number);
cnt[ans.size()-1]++;
vis[number]=1;
}
}
n=ans.size();
for(int i=0;i<n;i++)to[i]=i;
sort(to,to+n,cmp);
bool ok=0;
for(int i=0;i<n;i++)if(cnt[i]>1)ok=1;
if(!ok)printf("No duplicates.\n");
else
for(int i=0;i<n;i++)
{
int pos=to[i];
if(cnt[pos]==1)continue;
printf("%03d-%04d %d\n",ans[pos]/10000,ans[pos]%10000,cnt[pos]);
}
}
return 0;
}
K: Complex Congratulation β
題目兩個要求
1.影響力之和越大越好(恰好每個影響力都非負)
2.至少一半的人支援A&&至少一半的人支援B
既支援a又支援b的對1有好處又對2有好處,全部選中。支援1的和支援2的成對選中,對1有好處,對2沒影響。剩下的光支援一方但無法配對的和都不支援的選中影響力最大的k個人,k=同時支援ab的人數。
#include<cstdio>
#include<algorithm>
using namespace std;
int n,ab,a,b,no,ans;
int power[4][400005];
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
//freopen("input.in","r",stdin);
int x,y;
while(scanf("%d",&n)!=EOF)
{
ans=ab=a=b=no=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
if(x==11){ab++;power[0][ab]=y;}
else if(x==10){a++;power[1][a]=y;}
else if(x==1){b++;power[2][b]=y;}
else {no++;power[3][no]=y;}
}
for(int i=1;i<=ab;i++)ans+=power[0][i];
sort(power[a>b?1:2]+1,power[a>b?1:2]+1+(a>b?a:b),cmp);
for(int i=1;i<=min(a,b);i++)ans+=power[1][i]+power[2][i];
for(int i=min(a,b)+1;i<=(a>b?a:b);i++)power[3][++no]=power[a>b?1:2][i];
sort(power[3]+1,power[3]+1+no,cmp);
for(int i=1;i<=ab;i++)ans+=power[3][i];
printf("%d\n",ans);
}
return 0;
}
L: 只有我不在的世界β
lcm/a==b/gcd,故數量==b/gcd的個數==gcd的個數,列舉就行了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define pi (acos(-1))
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int t,n,m,a[100005];
char type[105],name[105];
int l,r,num;
int sum[100005];
int cnt[1005];
int main()
{
//freopen("input.in","r",stdin);
scanf("%d",&t);
while(t--)
{
int tot=0;
memset(cnt,0,sizeof(cnt));
scanf("%d",&n);
for(int i=1;i<=1000;i++)
{
int ans=gcd(n,i);
if(!cnt[ans])
{
cnt[ans]=1;
tot++;
}
}
printf("%d\n",tot);
}
return 0;
}
M: 在那天的雪停息之前β
模擬
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int t,n,m,a[100005];
char type[105],name[105];
int l,r,num;
int sum[100005];
int main()
{
//freopen("input.in","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
while(n!=1)
{
if(n&1)
{
printf("%d*3+1=%d\n",n,3*n+1);n=n*3+1;
}
else
{
printf("%d/2=%d\n",n,n/2);n=n/2;
}
}
if(t)puts("");
}
return 0;
}