伊蘇比的夢幻之旅(二)比賽題解

比賽地址:http://qscoj.cn/contest/22/java

第5-1關 吃餅(小數據)c++

分析:數據的範圍只有1-3,因此能夠將每種狀況手工計算出來。1刀最多可切2塊,2刀可切4塊,3刀可切7塊,4刀可切11塊。注意,本題的坑點在於在場的女性除了小卿卿的F位朋友,還包括小卿卿本身,因此吉祥餅上得切F+1刀。數組

標程:ide

#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.大數據

標程:spa

#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關 吃餅(大數據)code

分析:由第5-2關可知,S(N)=(N^2+N+2)/2,這題N的大小爲10^2333,故使用高精度的加法、乘法、除法即可解決此題。此題運算操做較多,需注意下進位的問題。或用JAVA中的大整數也能夠解決這個問題。blog

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、一、五、6的數,不管多少次方,其個位數仍是其自己;個位數爲二、三、七、8的數的乘方的個位數以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\n",ans);
    }
    if (k==3)
    {
        ans=modexp(m,n,1000);
        if (ans<100) printf("0");
        if (ans<10) printf("0");
        printf("%lld\n",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\n",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\n",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;
}
相關文章
相關標籤/搜索