比賽地址: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; }