Topcoder SRM 605 div1 题解

Posted 一只蒟篛酱的日常~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Topcoder SRM 605 div1 题解相关的知识,希望对你有一定的参考价值。

日常打卡~

Easy(250pts):

题目大意:你有n种汉堡包(统统吃掉~),每一种汉堡包有一个type值和一个taste值,你现在要吃掉若干个汉堡包,使得它们taste的总和*(不同的type值的个数)乘积越大,输出这个最大值。数据满足n<=50,type<=100,abs(taste)<=100000。

这题好像是个贪心,才不是呢啊哼~

首先我们发现,如果若干个汉堡包有同一个type值,那么我们可以把这一些汉堡包看成一个新的大汉堡包,它的type就是原来的type,它的taste就是取原先至少一个的最大taste之和,显然这一步是可以O(n)预处理完成的。

然后由于type不是很大,我们可以枚举我们选取了多少个type,

如果选择了k个type,那么一定是选择了taste最大的k个,然后乘以下,扫一遍k就好了。

时间复杂度O(n^2),代码如下:

 1 #include <bits/stdc++.h>
 2 #define Maxn 107
 3 #define inf 10000007
 4 using namespace std;
 5 int f[Maxn],g[Maxn];
 6 int cnt1,cnt2,n;
 7 class AlienAndHamburgers
 8 {
 9     public:
10     int getNumber(vector <int> type, vector <int> taste)
11     {
12         n=type.size();
13         for (int i=1;i<=100;i++)
14             f[i]=-inf;
15         for (int i=0;i<n;i++)
16             if (f[type[i]]<0) f[type[i]]=max(f[type[i]],taste[i]);
17             else if (taste[i]>0) f[type[i]]+=taste[i];
18         sort(f+1,f+100+1);
19         memset(g,0,sizeof(g));
20         g[100]=f[100];
21         for (int i=100-1;i;i--)
22             g[i]=f[i]+g[i+1];
23 //g[100+1-i] now means the most taste[i] can get to choose i types of food
24         int ans=0;
25         for (int i=1;i<=100;i++)
26             if (f[100+1-i]>-inf&&g[100+1-i]>0) ans=max(ans,g[100+1-i]*i);
27         return ans;
28     }
29 };

Medium(450pts):

题目大意:有2n个数1~2n,现在把它们分成两个集合A和B,满足A和B都有n个元素,且A中第i小的元素和B中第i小的元素的差的绝对值至少为K,求方案数,数据满足n<=50,K<=10。

我实在没有搞懂,为什么这题450分。。。

比较显然是个dp吧,我们来考虑怎么来描述一个状态,

在每一个状态下,都有两种数,第一种是已经被匹配的了,第二种是还没有被匹配的,

而没有被匹配的也有两种,

我们从大到小进行匹配,假设当前进行匹配的数为i,那么未被匹配的数一共有两种,

第一种是大于等于i+K的数,这些数可以随意被匹配,

第二种是i+1~i+K-1这些数,这些数不能和i匹配,

这两种数中,第一种数我们只关心它的个数,第二种则要关心位置,需要用2^k种状态描述出来,

然后直接转移就可以了,

时间复杂度O(n^2*2^K),代码如下:

 1 #include <bits/stdc++.h>
 2 #define modp 1000000007
 3 #define Maxn 107
 4 #define Maxk 10
 5 using namespace std;
 6 int f[Maxn][Maxn][1<<Maxk];
 7 bool vis[Maxn][Maxn][1<<Maxk];
 8 int n,k;
 9 class AlienAndSetDiv1
10 {
11     int tryit(int i, int j, int t)
12     {
13 //i means how many numbers left now
14 //j means how many numbers in set A can be free-matched
15 //t means the condition of the numbers in set A that cannot be free-matched
16         if (vis[i][j][t]) return f[i][j][t];
17         vis[i][j][t]=true;
18         int res=0;
19         if (i==0)
20         {
21             if (j==0&&t==0) res=1;
22             f[i][j][t]=res;
23             return res;
24         }
25         if (j==0&&t==0)
26         {
27 //all the i numbers are matched now
28             if (k==1) res=tryit(i-1,1,0); else res=tryit(i-1,0,1);
29             res=(2LL*res)%modp;
30             f[i][j][t]=res;
31             return res;
32         }
33         if (j>0)
34         {
35 //i get matched with a free-matched one
36             int nowt=2*t,nowj=j-1;
37 //the biggest one become free-matched
38             if (nowt&(1<<(k-1)))
39             {
40                 nowt-=1<<(k-1);
41                 ++nowj;
42             }
43             res=(res+tryit(i-1,nowj,nowt))%modp;
44         }
45         int nowt=2*t+1,nowj=j;
46         if (nowt&(1<<(k-1)))
47         {
48             nowt-=1<<(k-1);
49             ++nowj;
50         }
51         res=(res+tryit(i-1,nowj,nowt))%modp;
52         f[i][j][t]=res;
53         return res;
54     }
55     public:
56     int getNumber(int N, int K)
57     {
58         n=N,k=K;
59         memset(vis,false,sizeof(vis));
60         memset(f,0,sizeof(f));
61         return tryit(2*n,0,0);
62     }
63 };

Hard(1000pts):

题目大意:现在有一个数列,它是1~n的一个排列,我们每次可以进行一次操作:选取一段l~r,将l~r的数都变成l~r的最大值,现在可以进行不超过K次操作,求最后一共有多少种不同的可能。数据满足n<=200,k<=200。

怎么这题又是dp呀,自古TC出DP~

在dp之前,我们需要对这个奇奇怪怪的操作挖掘一些性质。

首先,一开始的n个数是不相同的,所以在整个操作过程中的任何时刻,相同的数永远都是连续的一段。

其次,在某次操作前,i的一段在j的一段的前面,那么操作之后i的这一段依然在j的这一段的前面。

有了这两个性质,差不多就可以dp了,我们考虑如何表述一个状态。

k表示当前最多可以操作几步,i表示当前从小到大判定第几个数,j表示新的数列的前j个数已经被确定,

那么我们就有f[k][i][j]=sigma(f[k-1][i-1][r])。

然而这样是O(n^4)的,对于n<=200显然会爆炸,我们考虑进行进一步的优化,

我们预处理出第i为什么情况下能变成j,那么一定是在原数列中,这两个数位置之前的数都小于等于j,

这样我们可以先预处理出某个位置可以变成什么数,时间复杂度O(n^3),

然后我们继续dp,除了上面描述的k,i,j,我们再用一个state表示当前是否处于匹配状态,显然state只能是true或者false,

于是考虑f[k][i][j][state]:

如果j>n,那么这已经是一个合法方案了,直接返回1;

如果i>n,那么这个方案不合法,直接返回0;

如果这两种情况都不满足,那么有两种情况:

第一种是当前数i不参与匹配,对答案贡献度是f[k][i+1][j][false];

第二种是当前数i参与匹配,我们没有必要再枚举它匹配到哪个位置,直接f[k-1][i][j+1][true]就可以了。

这里dp就完成了,时间复杂度O(n^3)。

所以整个题时间复杂度O(n^3),代码如下:

 1 #include <bits/stdc++.h>
 2 #define Maxn 207
 3 #define modp 1000000007
 4 using namespace std;
 5 int f[Maxn][Maxn][Maxn][2];
 6 bool vis[Maxn][Maxn][Maxn][2];
 7 bool check[Maxn][Maxn];
 8 int p[Maxn];
 9 int n,k;
10 class AlienAndPermutation
11 {
12     int tryit(int k, int i, int j, int state)
13     {
14         if (vis[k][i][j][state]) return f[k][i][j][state];
15         vis[k][i][j][state]=true;
16         if (j>n)
17         {
18 //the situation is valid
19             f[k][i][j][state]=1;
20             return f[k][i][j][state];
21         }
22         if (i>n)
23         {
24 //the situation is invalid
25             f[k][i][j][state]=0;
26             return f[k][i][j][state];
27         }
28 //the ith number isn‘t used
29         int res=tryit(k,i+1,j,0);
30 //the ith number is used
31         if (check[i][j])
32         {
33             if (state==1||(i==j)) res=(res+tryit(k,i,j+1,state))%modp;
34             else if (k>0) res=(res+tryit(k-1,i,j+1,1))%modp;
35         }
36         f[k][i][j][state]=res;
37         return res;
38     }
39     public:
40     int getNumber(vector <int> P, int K)
41     {
42         n=P.size(),k=K;
43         for (int i=1;i<=n;i++) p[i]=P[i-1];
44         memset(check,true,sizeof(check));
45         for (int i=1;i<=n;i++)
46             for (int j=1;j<=n;j++)
47                 for (int t=min(i,j);t<=i||t<=j;t++)
48                     if (p[t]>p[i]) check[i][j]=false;
49         memset(f,0,sizeof(f));
50         memset(vis,false,sizeof(vis));
51         return tryit(k,1,1,0);
52     }
53 };

 

以上是关于Topcoder SRM 605 div1 题解的主要内容,如果未能解决你的问题,请参考以下文章

Topcoder SRM 718 div1 level three 题解

Topcoder SRM 603 div1题解

Topcoder SRM 608 div1 题解

Topcoder SRM 604 div1题解

Topcoder SRM 607 div1题解

TopCoder SRM502 Div1 1000 动态规划