哈爾濱理工大學軟件與微電子學院程序設計競賽(同步賽)賽後總結

  https://ac.nowcoder.com/acm/contest/9536  

  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;
}
A

  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;
}
B

  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;
}
C

  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;
}
D

   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;
}
E

  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;
}
F

  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;
}
G

  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;
}
H

  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;
}
I

  之前的題都是有手就行,下面的題需要一些能力了。

  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;
}
J

  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;
}
K

  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;
}
L

  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;
}
M

  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;
}
N

  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;
}
O

  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;
}
P

  Q題是個結論題:1/n是有限小數當且僅當n的質因子只有2和5。這是因爲1和任意有限小數除以2,5都是有限小數,除以其他質數都是無限小數。於是把輸入進來的n一直除以2和5,看看是不是剩下個1即可。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章