• 伊苏比的梦幻之旅(二)比赛题解


    比赛地址:http://qscoj.cn/contest/22/

    第5-1关 吃饼(小数据)

    分析:数据的范围只有1-3,所以可以将每种情况手工计算出来。1刀最多可切2块,2刀可切4块,3刀可切7块,4刀可切11块。注意,本题的坑点在于在场的女性除了小卿卿的F位朋友,还包括小卿卿自己,所以吉祥饼上得切F+1刀。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int piece(int k)
    {
        if (k==1) return 2;
        if (k==2) return 4;
        if (k==3) return 7;
        if (k==4) return 11;
    }
    int main()
    {
        int m,f;
        cin>>m>>f;
        cout<<piece(m)+piece(f+1)<<endl;
        return 0;
    }

    第5-2关 吃饼(中数据)

    分析:设切N刀的最多饼块数为S(N),由第5-1关得S(1)=2;S(2)=4;S(3)=7;S(4)=11可以推出S(N)-S(N-1)=N,由此可以计算出S(N)的通项公式为S(N)=(N^2+N+2)/2,N虽然为10^9大小,但设变量时还是建议设成long long,不然相乘时会爆int.

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    long long S(long long k)
    {
        return (k*k+k+2)/2;
    }
    int main()
    {
        long long m,f;
        cin>>m>>f;
        cout<<S(m)+S(f+1)<<endl;
        return 0;
    }

    第5-3关 吃饼(大数据)

    分析:由第5-2关可知,S(N)=(N^2+N+2)/2,这题N的大小为10^2333,故使用高精度的加法、乘法、除法便可解决此题。此题运算操作较多,需注意下进位的问题。或用JAVA中的大整数也可以解决这个问题。

    C++标程:

    #include<bits/stdc++.h>
    using namespace std;
    int m[2500],f[2500];
    int m1[2500],f1[2500];
    int c1[5000],c2[5000],c3[5000];
    int main()
    {
        int i,j,lena,lenb;
        string a,b;
        bool flag;
        cin>>a>>b;
        lena=a.length();lenb=b.length();
        for(i=0;i<lena;i++)
            m[lena-1-i]=a[i]-48;
        for(i=0;i<lenb;i++)
            f[lenb-1-i]=b[i]-48;
        f[0]++;j=0;
        while (f[j]==10) {f[j]=0;j++;f[j]++;}
        for(i=0;i<2400;i++)
        {
            m1[i]=m[i];f1[i]=f[i];
        }
        m1[0]++;j=0;
        while (m1[j]==10) {m1[j]=0;j++;m1[j]++;}
        f1[0]++;j=0;
        while (f1[j]==10) {f1[j]=0;j++;f1[j]++;}
        for(i=0;i<2400;i++)
         for(j=0;j<2400;j++)
         {
            c1[i+j]+=m[i]*m1[j];
            c2[i+j]+=f[i]*f1[j];
         }
        for(i=0;i<4800;i++)
            c3[i]=c1[i]+c2[i];
        for(i=0;i<4800;i++)
        {
            j=c3[i]/10;c3[i]%=10;c3[i+1]+=j;
        }
        for(i=0;i<4800;i++)
        {
            if (c3[i]%2==0) c3[i]/=2;
            else {c3[i-1]+=5;c3[i]/=2;}
        }
        c3[0]+=2;j=0;flag=false;
        while(c3[j]>=10) {c3[j]-=10;j++;c3[j]++;}
        for(i=4800;i>=0;i--)
        {
            if (i==0 || c3[i]) flag=true;
            if (flag) printf("%d",c3[i]);
        }
        cout<<endl;
        return 0;
    }

    JAVA标程:

    import java.util.*;
    import java.math.*;
    public class Main{
         public static void main(String args[]){
            Scanner cin=new Scanner(System.in);
            BigInteger m,f,m1,f1,ans1,ans2,ans;
            m=cin.nextBigInteger();f=cin.nextBigInteger();
            f=f.add(BigInteger.valueOf(1));
            m1=m.add(BigInteger.valueOf(1));
            f1=f.add(BigInteger.valueOf(1));
            ans1=m.multiply(m1);
            ans1=ans1.add(BigInteger.valueOf(2));
            ans1=ans1.divide(BigInteger.valueOf(2));
            ans2=f.multiply(f1);
            ans2=ans2.add(BigInteger.valueOf(2));
            ans2=ans2.divide(BigInteger.valueOf(2));
            ans=ans1.add(ans2);
            System.out.println(ans);
        }
    }

    第6-1关 末位数(小数据)

    分析:求M^N的个位数,M和N只有10^4大小,故直接for循环一遍,每次相乘后%10就是最终的答案。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int m,n,k,i;
        cin>>m>>n>>k;
        for(i=1;i<=n;i++)
        {
            k*=m;k%=10;
        }
        cout<<k<<endl;
    }

    第6-2关 末位数(中数据)

    分析:求M^N的个位数,M和N有10^13大小,直接for肯定超时,所以我们可以通过分析下M的个位数,对于每一个M它的前几项的个位数找出他的规律。不难发现,个数为0、1、5、6的数,无论多少次方,其个位数还是其本身;个位数为2、3、7、8的数的乘方的个位数以4为周期在变化;个位数为4、9的数的乘方的个位数以2为周期在变化。分析出每一种情况,再特判一下任何一个数的0次方均为1,就可以AC了。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        long long m,n,k;
        cin>>m>>n>>k;
        if (n==0) {cout<<1<<endl;return 0;}
        m%=10;n%=4;
        if (m==0) k=0;
        if (m==1) k=1;
        if (m==2)
        {
            if (n==0) k=6;
            if (n==1) k=2;
            if (n==2) k=4;
            if (n==3) k=8;
        }
        if (m==3)
        {
            if (n==0) k=1;
            if (n==1) k=3;
            if (n==2) k=9;
            if (n==3) k=7;
        }
        if (m==4)
        {
            if (n==0) k=6;
            if (n==1) k=4;
            if (n==2) k=6;
            if (n==3) k=4;
        }
        if (m==5) k=5;
        if (m==6) k=6;
        if (m==7)
        {
            if (n==0) k=1;
            if (n==1) k=7;
            if (n==2) k=9;
            if (n==3) k=3;
        }
        if (m==8)
        {
            if (n==0) k=6;
            if (n==1) k=8;
            if (n==2) k=4;
            if (n==3) k=2;
        }
        if (m==9)
        {
            if (n==0) k=1;
            if (n==1) k=9;
            if (n==2) k=1;
            if (n==3) k=9;
        }
        cout<<k<<endl;
        return 0;
    }

    第6-3关 末位数(大数据)

    分析:这个题要求M^N的后k位数,其实就是M^N%P的问题,用到的知识点是快速幂。其中,P=10^k,注意输出时通过一些判断来保证有k位。

    #include<bits/stdc++.h>
    using namespace std;
    long long modexp(long long a,long long b,int mod)
    {
        long long res=1;
        while (b)
        {
            a=a%mod;
            if (b & 1) res=res*a%mod;
            b=b>>1;
            a=a*a%mod;
        }
        return res;
    }
    int main()
    {
        long long m,n,k,ans;
        cin>>m>>n>>k;
        if (k==1)
        {
            ans=modexp(m,n,10);
            printf("%lld",ans);
        }
        if (k==2)
        {
            ans=modexp(m,n,100);
            if (ans<10) printf("0");
            printf("%lld
    ",ans);
        }
        if (k==3)
        {
            ans=modexp(m,n,1000);
            if (ans<100) printf("0");
            if (ans<10) printf("0");
            printf("%lld
    ",ans);
        }
        if (k==4)
        {
            ans=modexp(m,n,10000);
            if (ans<1000) printf("0");
            if (ans<100) printf("0");
            if (ans<10) printf("0");
            printf("%lld
    ",ans);
        }
        if (k==5)
        {
            ans=modexp(m,n,100000);
            if (ans<10000) printf("0");
            if (ans<1000) printf("0");
            if (ans<100) printf("0");
            if (ans<10) printf("0");
            printf("%lld
    ",ans);
        }
        return 0;
    }

    第7-1关 排队(小数据)

    分析:数据范围只有3,手工计算所有情况,发现只有“3 1 2”这种情况不行,便特判下这种情况输出“Fail”,其他均输出“Success”.

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int a[4],i,n;
        cin>>n;
        for(i=1;i<=n;i++)
            cin>>a[i];
        if (n==3 && a[1]==3 && a[2]==1 && a[3]==2) cout<<"Fail"<<endl;
        else cout<<"Success"<<endl;
        return 0;
    }

    第7-2关 排队(中数据)

    分析:数据范围有10,可以通过DFS方式把所有的入栈出栈的可能计算出来,再判断是否与汪老师要求的序列进行匹配。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int s[25],a[13],b[13],n;
    int t[2];
    bool flag;
    stack<int> st;
    void dfs(int k)
    {
        int i,j,cnt;
        if (k==2*n+1)
        {
            if (t[0]!=t[1]) return ;
            cnt=0;j=1;while(!st.empty()) st.pop();
            for(i=1;i<=2*n;i++)
            {
                if (s[i]==0) st.push(j++);
                else {cnt++;b[cnt]=st.top();st.pop();}
            }
            bool g;
            g=true;
            for(i=1;i<=n;i++)
                if (a[i]!=b[i]) g=false;
            if (g) flag=true;
            return ;
        }
        for(i=0;i<2;i++)
        {
            s[k]=i;t[i]++;
            if (t[1]<=t[0]) dfs(k+1);
            t[i]--;
        }
    }
    int main()
    {
        int i;
        cin>>n;
        for(i=1;i<=n;i++)
            cin>>a[i];
        flag=false;dfs(1);
        if (flag) cout<<"Success"<<endl;
        else cout<<"Fail"<<endl;
        return 0;
    }

    第7-3关 排队(大数据)

    分析:其实这道题就是一道模拟题。用一个光标记录新队列当前元素的位置,一开始这个位置为1,先将原队列的头元素压入栈中,再不断判断栈顶元素是否为新队列指向的元素,如果是的话就弹出栈顶元素,并且将新队列位置右移;不是的话就再从原队列中压入元素。最后检查栈是否为空或者光标是否移到最右边的位置,来判断是否排队成功。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    stack<int> q;
    int main()
    {
        int n,i,j;
        int a[60010];
        cin>>n;
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        j=1;
        for(i=1;i<=n;i++)
        {
            q.push(i);
            while(!q.empty() && q.top()==a[j]) {q.pop();j++;}
        }
        if (q.empty()) cout<<"Success"<<endl;
        else cout<<"Fail"<<endl;
        return 0;
    }

    第8-1关 默契值(小数据)

    分析:如果只有2名队员,答案就是他们的默契值;如果有4名队员,刘老师必须得跟其中与自己默契值最大的队员组队,在合理的可能中,再判断剩下两名队员哪组默契值最小,两种默契值相加就是答案。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int a,b,c,d,e,f,n,maxx,minx;
        cin>>n;
        if (n==2)
        {
            cin>>a;
            cout<<a<<endl;
            return 0;
        }
        cin>>a>>b>>c>>d>>e>>f;
        maxx=max(a,max(b,c));minx=0x3f3f3f3f;
        if (a==maxx) minx=min(minx,f);
        if (b==maxx) minx=min(minx,e);
        if (c==maxx) minx=min(minx,d);
        cout<<maxx+minx<<endl;
        return 0;
    }

    第8-2关 默契值(中数据)

    分析:队员最大有10名,所以可以用全排列的方法做这道题。奇偶相邻的两名队员便为配对的队员,得保证刘老师得跟与自己默契值最大的队员配对,再从剩下的队员找配对的最小默契值和。还是注意特判下N=2的情况。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n,i,j,k,maxx,minx,res;
        int a[25][25],b[25];
        cin>>n;
        for(i=1;i<=n-1;i++)
            for(j=1;j<=n-i;j++)
                cin>>a[i][i+j];
        if (n==2)
        {
            cout<<a[1][2]<<endl;
            return 0;
        }
        maxx=-1;minx=0x3f3f3f3f;
        for(i=2;i<=n;i++)
            maxx=max(a[1][i],maxx);
        for(i=1;i<=n;i++)
            b[i]=i;
        do
        {
            if (a[1][b[2]]<maxx) continue;res=0;
            for(i=2;i<=n/2;i++)
            {
                j=b[2*i-1];k=b[2*i];
                res+=a[min(j,k)][max(j,k)];
            }
            minx=min(res,minx);
        }while(next_permutation(b+2,b+1+n));
        cout<<maxx+minx<<endl;
        return 0;
    }

    第8-3关 默契值(大数据)

    分析:N的大小为20,用全排列或者DFS的方式肯定会超时。所以可以采用DP+记忆化搜索的方式来完成此题。需要开一个1<<20的数组,将每个数转化为二进制,如果某一位的值为0,则表明该种情况不包括其位置所对应的队员;如果某一位的值为1,则表明该种情况包括其位置所对应的队员。初始化时将d[x]所有值赋为1个非常大的数,将d[0]赋为0.在dp函数中每次先找出当前没配对的第1名队员,再从剩下没配对的队员中依次寻找与它配对,将s一开始赋值为(1<<n)-1;s=s^(1<<i)^(1<<j)就表示去掉第i名队员和第j名队员剩下的情况。转移方程便为d[s]=min(d[s],dp(s^(1<<i)^(1<<j))+a[i][j]);总之,只要将这道题的方法搞清楚了,解决它也不是什么难事。

    标程:

    #include<bits/stdc++.h>
    using namespace std;
    int a[20][20],d[1<<20];
    int n;
    int inf=0x3f3f3f3f;
    int dp(int s)
    {
        int i,j;
        if (d[s]!=inf) return d[s];
        for(i=0;i<n;i++)
            if (s & (1<<i)) break;
        for(j=i+1;j<n;j++)
            if (s & (1<<j)) d[s]=min(d[s],dp(s^(1<<j)^(1<<i))+a[i][j]);
        return d[s];
    }
    int main()
    {
        int t,s,maxx,minx,i,j;
        cin>>n;
        for(i=0;i<n-1;i++)
         for(j=1;j<n-i;j++)
          cin>>a[i][i+j];
        if (n==2)
        {
            cout<<a[0][1]<<endl;
            return 0;
        }
        maxx=-1;minx=inf;
        for(i=1;i<n;i++)
            if (a[0][i]>maxx) maxx=a[0][i];
        for(i=1;i<n;i++)
        {
            if (a[0][i]==maxx)
            {
                for(j=0;j<(1<<n);j++)
                    d[j]=inf;
                s=(1<<n)-1;
                s=s^(1<<0)^(1<<i);
                d[0]=0;
                minx=min(minx,dp(s));
            }
        }
        cout<<maxx+minx<<endl;
        return 0;
    }
  • 相关阅读:
    jdbc连接数据库 url
    解决IntelliJ IDEA 使用 TOMCAT 中文乱码问题
    web.xml 4.0 头部信息
    jar包冲突解决方案
    idea 快捷键
    基于单片机的车辆防碰撞及自动刹车系统(STC89C52RC芯片+超声波传感器HC-SR04+液晶屏1602+继电器+蜂鸣器)
    电子时钟万年历+51单片机+1602液晶屏+DS1302+DS18B20+按键
    1008 数组元素循环右移问题(PAT)
    1007 素数对猜想(PAT)
    1006 换个格式输出整数(PAT)
  • 原文地址:https://www.cnblogs.com/cs-lyj1997/p/6821655.html
Copyright © 2020-2023  润新知