1. 程式人生 > >廣東工業大學2018新生杯決賽

廣東工業大學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;
}