1. 程式人生 > >Topcoder SRM 608 div1 題解

Topcoder SRM 608 div1 題解

b+ 輸出 har 不能 include c++ point pac easy

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 題解