2016百度之星 - 初赛(Astar Round2A)解题报告
此文章可以使用目錄功能喲↑(點擊上方[+])
有點智商捉急,第一題卡了好久,看來不服老,不服笨是不行的了...以下是本人目前的題解,有什么疑問歡迎提出
鏈接→2016"百度之星" - 初賽(Astar Round2A)
?Problem 1001 All X
Accept: 0 ? ?Submit: 0
Time Limit: 2000/1000 mSec(Java/Others)????Memory Limit : 65536 KB
?Problem Description
F(x,m) 代表一個全是由數字x組成的m位數字。請計算,以下式子是否成立:
? ? ? ?F(x,m) mod k ≡ c
?Input
? ? ? 第一行一個整數T,表示T組數據。 每組測試數據占一行,包含四個數字x,m,k,c1≤x≤9
1≤m≤10,000,000,000
??? 0≤c<k≤10,000
?Output
對于每組數據,輸出兩行: 第一行輸出:"Case #i:"。i代表第i組測試數據。 第二行輸出“Yes” 或者 “No”,代表四個數字,是否能夠滿足題目中給的公式。
?Sample Input
31 3 5 2
1 3 5 1
3 5 99 69
?Sample Output
Case #1:No
Case #2:
Yes
Case #3:
Yes
Hint
對于第一組測試數據:111 mod 5 = 1,公式不成立,所以答案是”No”,而第二組測試數據中滿足如上公式,所以答案是 “Yes”。
?Problem Idea
解題思路:此題求的是m個數字x組成的m位數對k取模是否等于c,從m的大小可以看出此題想利用同余定理1位1位計算是解決不了了,這樣我們就得換種思路,首先,我們提取一個x,那剩下的就是m個1,如下:
這個數要mod k ,那這個數應該怎么表示呢?
就這樣轉化了,然后10^m可以通過快速冪解決,但是很明顯,除以9操作怎么辦,除法取模,余數是會改變的,逆元?但是9和k不一定互質,且k也不一定是質數,所以擴展歐幾里得和費馬小定理都不能用了,束手無策
好吧,這里提供一種小方法
就這樣經過幾步轉化,我求d不需要進行除法取模了,那我上面的問題不就解決了?對的
在這里,我要提一點更優化的操作(雖然此題優化效果不是太明顯)
首先我們知道歐拉定理
φ(k)為歐拉函數,表示k以內與k互質的數的個數
而我們在求解10^m的時候就可以借用歐拉定理降冪
不好意思,上面的歐拉定理降冪誤導了大家,歐拉定理成立是有條件的,即a與k需要互質,本題10與k不一定互質
只能說題目數據才水,本人考慮不周,不過去掉歐拉定理這部分,代碼還是對的,降冪這點小優化沒有還可以靠快速冪彌補,不要緊
題目鏈接→HDU 5690?All X
?Source Code
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 100005; const int M = 40; const int inf = 100000000; //const int mod = 2009; __int64 Quick_Mod(__int64 a, __int64 b, __int64 mod) {__int64 res = 1,term = a % mod;while(b){if(b & 1) res = (res * term) % mod;term = (term * term) % mod;b >>= 1;}return res; } /*__int64 euler(__int64 n) {__int64 ans=1;__int64 i;for(i=2;i*i<=n;i++){if(n%i==0){n/=i;ans*=i-1;while(n%i==0){n/=i;ans*=i;}}}if(n>1)ans*=n-1;return ans; }*/ int main() {int t,p=1,i;__int64 m,ans,x,c,k;scanf("%d",&t);while(t--){scanf("%I64d%I64d%I64d%I64d",&x,&m,&k,&c);k*=9;//m%=euler(k);ans=(Quick_Mod(10,m,k)+k-1)%k;ans/=9;k/=9;ans=(ans*x)%k;//printf("%I64d\n",ans);printf("Case #%d:\n",p++);if(ans==c)puts("Yes");elseputs("No");}return 0; }
?Problem 1002 Sitting in Line
Accept: 0 ? ?Submit: 0
Time Limit: 10000/5000 mSec(Java/Others)????Memory Limit : 262144 KB
?Problem Description
度度熊是他同時代中最偉大的數學家,一切數字都要聽命于他。現在,又到了度度熊和他的數字仆人們玩排排坐游戲的時候了。游戲的規則十分簡單,參與游戲的N個整數將會做成一排,他們將通過不斷交換自己的位置,最終達到所有相鄰兩數乘積的和最大的目的,參與游戲的數字有整數也有負數。度度熊為了在他的數字仆人面前展現他的權威,他規定某些數字只能在坐固定的位置上,沒有被度度熊限制的數字則可以自由地交換位置。
?Input
? ? ? 第一行一個整數T,表示T組數據。 每組測試數據將以如下格式從標準輸入讀入:??? 第一行,整數N(1≤N≤16),代表參與游戲的整數的個數。從第二行到第 (N + 1)行,每行兩個整數,ai(?10000≤a?i≤10000)、p?i(p?i=?1 或 0≤p?i<N),以空格分割。a?i代表參與游戲的數字的值,p?i代表度度熊為該數字指定的位置,如果p?i=?1,代表該數字的位置不被限制。度度熊保證不會為兩個數字指定相同的位置。?Output
第一行輸出:"Case #i:"。i代表第i組測試數據。
第二行輸出數字重新排列后最大的所有相鄰兩數乘積的和,即
?Sample Input
26
-1 0
2 1
-3 2
4 3
-5 4
6 5
5
40 -1
50 -1
30 -1
20 -1
10 -1
?Sample Output
Case #1:-70
Case #2:
4600
?Problem Idea
解題思路:要求,很顯然是道DP題
首先我們假設dp[1<<16][16],第一維可以表示成一個16位二進制數,其中,二進制數的第i位如果為1表示a[i]已經選擇好放的位置,否則即a[i]還沒有選定位置;dp數組第二維表示該序列目前以a[i]結尾
故dp[i][j]就表示在狀態i下,以a[j]結尾的序列的值
對于dp[i][j],i這個狀態已經填了x個數(x為i的二進制表示下1的個數),我們準備填第x+1個數時,如果當前位置必填某個數,那么,就只更新以規定的這個數結尾轉移方程如果沒有那就枚舉那么可以任意放的數來更新相應的狀態及答案
故而可以得到轉移方程
dp還是比較難理解的,有什么不明白的地方,歡迎咨詢
題目鏈接→HDU 5691 Sitting in Line
?Source Code
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 #define bitnum(a) __builtin_popcount(a) using namespace std; const int N = 20; const int M = 1<<16; const int inf = 1600000000; const int mod = 2009; int a[N],dp[M][N],v[N],p[N]; int main() {int T,i,j,k,n,q=1,U,cnt,Max;scanf("%d",&T);while(T--){memset(v,-1,sizeof(v));scanf("%d",&n);for(i=0;i<n;i++){scanf("%d%d",&a[i],&p[i]);if(p[i]!=-1)v[p[i]]=i;}for(i=0;i<(1<<n);i++)for(j=0;j<n;j++)dp[i][j]=-inf;if(v[0]!=-1)dp[1<<v[0]][v[0]]=0;elsefor(i=0;i<n;i++)if(p[i]==-1)dp[1<<i][i]=0;for(U=(1<<n),i=1;i<U;i++)for(j=0;j<n;j++)//a[j]結尾if(i&(1<<j)){for(k=0;k<n;k++)//a[k]未選if(!(i&(1<<k))){cnt=bitnum(i);if(v[cnt]==-1&&!(p[k]!=-1&&p[k]!=cnt)||v[cnt]==k)dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]+a[j]*a[k]);}}for(Max=-inf,i=0;i<n;i++)Max=max(Max,dp[U-1][i]);printf("Case #%d:\n%d\n",q++,Max);}return 0; }?Problem 1005 BD String
Accept: 0 ? ?Submit: 0
?Time Limit: 2000/1000 mSec(Java/Others)????Memory Limit : 65536 KB
?Problem Description
眾所周知,度度熊喜歡的字符只有兩個:B和D。
今天,它發明了一種用B和D組成字符串的規則:
S(1)=B
S(2)=BBD
S(3)=BBDBBDD
…
S(n)=S(n-1)+B+reverse(flip(S(n-1))
其中,reverse(s)指將字符串翻轉,比如reverse(BBD)=DBB,flip(s)指將字符串中的B替換為D,D替換為B,比如flip(BBD)=DDB。
雖然度度熊平常只用它的電腦玩連連看,這絲毫不妨礙這臺機器無與倫比的運算速度,目前它已經算出了S()的內容,但度度熊畢竟只是只熊,一次讀不完這么長的字符串。它現在想知道,這個字符串的第L位(從1開始)到第R位,含有的B的個數是多少?
?Input
第一行一個整數T,表示T(1≤T≤1000) 組數據。每組數據包含兩個數L和R(1≤L≤R≤) 。?Output
對于每組數據,輸出S()表示的字符串的第L位到第R位中B的個數。
?Sample Input
31 3
1 7
4 8
?Sample Output
24
3
?Problem Idea
解題思路:從字符串規則可以看出以下幾點
①S(n)的串長度為;
②S(n)中B的個數為個(以正中間的B為中心,假設左邊有x個B,那么右邊有個,即左邊B的個數+右邊B的個數=S(n-1)的串長度)
③遠大于,故只是嚇唬我們的
由上述幾點可知,此題并沒有表面上那么嚇人
要求區間[l,r]內B的個數,我們可以轉化為求[1,r]-[1,l-1]
而求區間[1,x]內B的個數,又可以如上述第②條所說,拆成3段,遞歸求解
比如x=12時,S=BBDBBDDBBBDD……
拆成3段如下:
右邊4個是多余的,但是因為右邊是由reverse+flip得到的,求右邊4個中B的個數可以轉化成求4-([1,7]中B的個數-[1,3]中B的個數)
而[1,3]中的個數又是得遞歸求解的
這題遞歸講得比較繞,要是小伙伴沒明白的,可以留下評論,我會及時回復的
題目鏈接→HDU 5694?BD String
?Source Code
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 100005; const int M = 40; const int inf = 100000000; const int mod = 2009; __int64 dfs(__int64 x) {if(!x)return 0;__int64 m=0,ans,res;while(m<x)m=m*2+1;m=(m-1)/2;ans=(m+1)/2;res=x-m-1;return ans+1+res-(ans-dfs(m-res)); } int main() {int t;__int64 l,r;scanf("%d",&t);while(t--){scanf("%I64d%I64d",&l,&r);printf("%I64d\n",dfs(r)-dfs(l-1));}return 0; }
?Problem 1006 Gym Class
Accept: 0 ? ?Submit: 0?
Time Limit: 6000/1000 mSec(Java/Others)????Memory Limit : 65536 KB
?Problem Description
眾所周知,度度熊喜歡各類體育活動。
今天,它終于當上了夢寐以求的體育課老師。第一次課上,它發現一個有趣的事情。在上課之前,所有同學要排成一列, 假設最開始每個人有一個唯一的ID,從1到N,在排好隊之后,每個同學會找出包括自己在內的前方所有同學的最小ID,作為自己評價這堂課的分數。麻煩的是,有一些同學不希望某個(些)同學排在他(她)前面,在滿足這個前提的情況下,新晉體育課老師——度度熊,希望最后的排隊結果可以使得所有同學的評價分數和最大。
?Input
第一行一個整數T,表示T(1≤T≤30) 組數據。對于每組數據,第一行輸入兩個整數N和M (1≤N≤100000,0≤M≤100000),分別表示總人數和某些同學的偏好。接下來M行,每行兩個整數A 和B(1≤A,B≤N),表示ID為A的同學不希望ID為B的同學排在他(她)之前。你可以認為題目保證至少有一種排列方法是符合所有要求的。?Output
對于每組數據,輸出最大分數 。
?Sample Input
31 0
2 1
1 2
3 1
3 1
?Sample Output
12
6
?Problem Idea
解題思路:眾所周知,為了使每個人給的評分盡可能高,在沒有條件的情況下,必定是ID高的排前面來得最優
但是度度熊沒有那么善良
ID為B的同學不能排在A前面,好吧,怎么做呢?
對于這種調度問題,我們不妨用拓撲排序來求解
假設B不能排在A前面,那么我就在AB之間畫一條從A指向B的邊,那么我們可以得到一幅有向圖
我們要按ID從大往小排,同時要考慮當前這位同學是否有特殊要求
上面有向圖中,凡入度為0的結點,表示沒有同學不希望該同學排在它的前面,故該同學可以按照ID從大往小排
所以此題的做法是,每次將入度為0的結點放入優先隊列中,選取ID最大的結點先排,然后將該ID的同學討厭的所有同學入度-1,若入度變為0同樣要放入優先隊列判斷ID先后,這里建圖可以鄰接表實現,也可以利用一些vector
題目鏈接→HDU 5695?Gym Class
?Source Code
/*Sherlock and Watson and Adler*/ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<set> #include<cmath> #include<complex> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 100005; const int M = 40; const int inf = 100000000; const int mod = 2009; struct cmp2 {bool operator ()(int &a,int &b){return a<b;//最大值優先} }; int n, m; int indegree[N]; priority_queue<int,vector<int>,cmp2> q;//最大值優先 vector<int> v[N]; int main() {int t,i,a,b,p,Min;__int64 ans;scanf("%d",&t);while(t--){ans=0;Min=inf;memset(indegree,0,sizeof(indegree));for(i=1;i<=n;i++)v[i].clear();while(!q.empty())q.pop();scanf("%d%d",&n,&m);for(i=0;i<m;i++){scanf("%d%d",&a,&b);indegree[b]++;v[a].push_back(b);}for(i=1;i<=n;i++)if(!indegree[i])q.push(i);while(!q.empty()){p=q.top();q.pop();Min=min(p,Min);ans+=Min;for(i=0;i<v[p].size();i++){indegree[v[p][i]]--;if(!indegree[v[p][i]])q.push(v[p][i]);}}printf("%I64d\n",ans);}return 0; } 菜鳥成長記
總結
以上是生活随笔為你收集整理的2016百度之星 - 初赛(Astar Round2A)解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为H3C交换机+Radius+mysq
- 下一篇: 双11女装数据大曝光!淘品牌大势已去