• 哈尔滨理工大学软件与微电子学院程序设计竞赛(同步赛)赛后总结


      链接 

      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即可。

    #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;
    }
    Q

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

      通过仔细观察大胆猜测可以得出,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;
        
    }
    G

      

  • 相关阅读:
    github使用
    部署flask
    docker部署路飞学城
    centos7安装dnsmasq局域网dns
    消息队列rabbitmq
    记录腾讯云中矿机病毒处理过程(重装系统了fu*k)
    Golang基础
    git协同开发
    gitlab与pycharm结合
    github与gitlab与git三个基佬的故事
  • 原文地址:https://www.cnblogs.com/qywyt/p/14292918.html
Copyright © 2020-2023  润新知