Topcoder SRM 608 div1 題解
Easy(300pts):
題目大意:有n個盒子,一共有S個蘋果,每個盒子有多少個蘋果不知道,但是知道每個盒子的蘋果下限和上限。現在要至少選擇X個蘋果,問如果要保證無論如何都能獲得至少X個蘋果,至少需要選擇多少個盒子。數據滿足n<=50。
首先第一個方面,如果我們選擇的盒子的下限大於等於X,那麽顯然我們一定可以獲得那麽多的蘋果,
所以我們將盒子的下限排序,然後從大到小累加即可。
另一方面,如果我們沒有選擇的盒子的上限小於等於S-X,那麽顯然我們也一定可以獲得那麽多的蘋果,
於是我們再按照上限排序,然後掃一遍累加即可。
時間復雜度O(nlogn),代碼如下:
1 #include <bits/stdc++.h> 2#define Maxn 57 3 using namespace std; 4 int n; 5 int l[Maxn],r[Maxn]; 6 class MysticAndCandies 7 { 8 public: 9 int minBoxes(int C, int X, vector <int> low, vector <int> high) 10 { 11 n=low.size(); 12 for (int i=1;i<=n;i++) l[i]=low[i-1]; 13 for(int i=1;i<=n;i++) r[i]=high[i-1]; 14 sort(l+1,l+n+1); 15 sort(r+1,r+n+1); 16 for (int i=1;i<n+1-i;i++) swap(l[i],l[n+1-i]),swap(r[i],r[n+1-i]); 17 int ans,sum1=0,sum2=0; 18 for (int i=1;i<=n;i++) sum2+=r[i]; 19 for (ans=1;ans<=n;ans++) 20 {21 sum1+=l[ans]; 22 sum2-=r[ans]; 23 if (sum1>=X||C-sum2>=X) break; 24 } 25 return ans; 26 } 27 };
Medium(600pts):
題目大意:給出一個n個點的有向圖,假設長度為L的路徑一共有S條(路徑可以經過重復的點多次,S也可以是無窮大),問當L非常大的時候,S的量級是L的幾次方。當然,有可能S不能用L的幾次方表示,那麽輸出-1。數據滿足n<=50。
通過題面來看,就感覺這題很厲害。。。
我們先從一個環來考慮,一個環的長度為L的路徑顯然只有有數條,那麽這個時候S就是L的一次方量級。
然後我們來考慮一個強聯通分量,如果這個強聯通分量不僅僅只是一個環,那麽路徑條數就是指數級別的了。
回到原題,我們把原圖中的強聯通分量全部求出來,
至少圖變成了一個DAG,然後發現所有的SCC必須是環,
然後差不多dp之類的都可以做了。
由於這道題n<=50,所以根本不需要什麽Tarjan,直接floyed就行了。
時間復雜度O(n^3),代碼如下:
1 #include <bits/stdc++.h> 2 #define Maxn 57 3 using namespace std; 4 bool vis[Maxn][Maxn]; 5 int fa[Maxn],sum[Maxn],sumedge[Maxn]; 6 int r[Maxn],f[Maxn]; 7 int n; 8 class BigO 9 { 10 public: 11 int minK(vector <string> graph) 12 { 13 n=graph.size(); 14 for (int i=0;i<n;i++) 15 for (int j=0;j<n;j++) 16 if (graph[i][j]==‘Y‘) vis[i][j]=true; else vis[i][j]=false; 17 for (int i=0;i<n;i++) 18 vis[i][i]=true; 19 for (int k=0;k<n;k++) 20 for (int i=0;i<n;i++) 21 for (int j=0;j<n;j++) 22 if (vis[i][k]&&vis[k][j]) vis[i][j]=true; 23 memset(sum,0,sizeof(sum)); 24 for (int i=0;i<n;i++) 25 for (int j=0;j<n;j++) 26 if (vis[i][j]&&vis[j][i]) 27 { 28 fa[i]=j; 29 ++sum[j]; 30 break; 31 } 32 memset(sumedge,0,sizeof(sumedge)); 33 for (int i=0;i<n;i++) 34 for (int j=0;j<n;j++) 35 if (graph[i][j]==‘Y‘&&fa[i]==fa[j]&&i!=j) 36 ++sumedge[fa[i]]; 37 memset(r,0,sizeof(r)); 38 memset(f,0,sizeof(f)); 39 for (int i=0;i<n;i++) 40 { 41 //the SCC is more than a circle 42 if (sumedge[i]>sum[i]) return -1; 43 //the SCC is more than a point 44 if (sumedge[i]!=0) r[i]=1; 45 f[i]=r[i]; 46 } 47 for (int T=0;T<n;T++) 48 for (int i=0;i<n;i++) 49 for (int j=0;j<n;j++) 50 if (fa[i]!=fa[j]&&graph[i][j]==‘Y‘) 51 f[fa[j]]=max(f[fa[j]],f[fa[i]]+r[fa[j]]); 52 int res=0; 53 for (int i=0;i<n;i++) 54 res=max(f[i]-1,res); 55 return res; 56 } 57 };
Hard(900pts):
題目大意:有一個機器人在x軸上,初始位置為0,它接受到了一系列指令,每次向左一個單位或者向右一個單位。如果現在在左邊界上,那麽就不能再往左了,向左的指令會被忽略;如果現在在右邊界上,那麽就不能再往右了,向右的指令會被忽略。現在對於minA<=A<=maxA,minB<=B<=maxB,求出以A為左邊界,B為右邊界的最終位置的總和,數據滿足所有數<=5000。
這題是個神結論題,不打算多說。。。
我們假設邊界都是無窮大的時候,求出出現過的最左側位置和最右側位置。
如果A和B分別大於等於兩邊邊界,那麽答案就是最終位置。
如果不是的話,有一個結論就是(a,b)等於(a-1,b+1)-1,然後按照差暴力就可以了。
時間復雜度O(nX+X^2),代碼如下:
1 #include <bits/stdc++.h> 2 #define Maxa 5007 3 using namespace std; 4 int ans[Maxa][Maxa]; 5 string s; 6 long long res=0; 7 class OneDimensionalRobot 8 { 9 public: 10 long long theSum(vector <string> commands1, vector <string> commands2, int minA, int maxA, int minB, int maxB) 11 { 12 s.clear(); 13 for (int i=0;i<commands1.size();i++) s+=commands1[i]; 14 for (int i=0;i<commands2.size();i++) s+=commands2[i]; 15 int left=0,right=0,pos=0; 16 for (int i=0;i<s.length();i++) 17 { 18 if (s[i]==‘R‘) ++pos; else --pos; 19 if (-pos>left) left=-pos; 20 if (pos>right) right=pos; 21 } 22 memset(ans,0,sizeof(ans)); 23 for (int i=minA;i<=maxA;i++) 24 for (int j=minB;j<=maxB;j++) 25 { 26 if (i>=left&&j>=right) ans[i][j]=pos; else 27 if (i==minA||j==maxB) 28 { 29 int now=0; 30 for (int k=0;k<s.length();k++) 31 { 32 if (s[k]==‘R‘) ++now; else --now; 33 if (-now>i) now=-i; 34 if (now>j) now=j; 35 } 36 ans[i][j]=now; 37 } else 38 { 39 ans[i][j]=ans[i-1][j+1]; 40 if (left>i-1||right>j) --ans[i][j]; 41 } 42 } 43 for (int i=minA;i<=maxA;i++) 44 for (int j=minB;j<=maxB;j++) 45 res+=ans[i][j]; 46 return res; 47 } 48 };
Topcoder SRM 608 div1 題解