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),代码如下:
#include <bits/stdc++.h>
#define Maxn 107
#define inf 10000007
using namespace std;
int f[Maxn],g[Maxn];
int cnt1,cnt2,n;
class AlienAndHamburgers
{
public:
int getNumber(vector <int> type, vector <int> taste)
{
n=type.size();
for (int i=;i<=;i++)
f[i]=-inf;
for (int i=;i<n;i++)
if (f[type[i]]<) f[type[i]]=max(f[type[i]],taste[i]);
else if (taste[i]>) f[type[i]]+=taste[i];
sort(f+,f++);
memset(g,,sizeof(g));
g[]=f[];
for (int i=-;i;i--)
g[i]=f[i]+g[i+];
//g[100+1-i] now means the most taste[i] can get to choose i types of food
int ans=;
for (int i=;i<=;i++)
if (f[+-i]>-inf&&g[+-i]>) ans=max(ans,g[+-i]*i);
return ans;
}
};
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),代码如下:
#include <bits/stdc++.h>
#define modp 1000000007
#define Maxn 107
#define Maxk 10
using namespace std;
int f[Maxn][Maxn][<<Maxk];
bool vis[Maxn][Maxn][<<Maxk];
int n,k;
class AlienAndSetDiv1
{
int tryit(int i, int j, int t)
{
//i means how many numbers left now
//j means how many numbers in set A can be free-matched
//t means the condition of the numbers in set A that cannot be free-matched
if (vis[i][j][t]) return f[i][j][t];
vis[i][j][t]=true;
int res=;
if (i==)
{
if (j==&&t==) res=;
f[i][j][t]=res;
return res;
}
if (j==&&t==)
{
//all the i numbers are matched now
if (k==) res=tryit(i-,,); else res=tryit(i-,,);
res=(2LL*res)%modp;
f[i][j][t]=res;
return res;
}
if (j>)
{
//i get matched with a free-matched one
int nowt=*t,nowj=j-;
//the biggest one become free-matched
if (nowt&(<<(k-)))
{
nowt-=<<(k-);
++nowj;
}
res=(res+tryit(i-,nowj,nowt))%modp;
}
int nowt=*t+,nowj=j;
if (nowt&(<<(k-)))
{
nowt-=<<(k-);
++nowj;
}
res=(res+tryit(i-,nowj,nowt))%modp;
f[i][j][t]=res;
return res;
}
public:
int getNumber(int N, int K)
{
n=N,k=K;
memset(vis,false,sizeof(vis));
memset(f,,sizeof(f));
return tryit(*n,,);
}
};
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),代码如下:
#include <bits/stdc++.h>
#define Maxn 207
#define modp 1000000007
using namespace std;
int f[Maxn][Maxn][Maxn][];
bool vis[Maxn][Maxn][Maxn][];
bool check[Maxn][Maxn];
int p[Maxn];
int n,k;
class AlienAndPermutation
{
int tryit(int k, int i, int j, int state)
{
if (vis[k][i][j][state]) return f[k][i][j][state];
vis[k][i][j][state]=true;
if (j>n)
{
//the situation is valid
f[k][i][j][state]=;
return f[k][i][j][state];
}
if (i>n)
{
//the situation is invalid
f[k][i][j][state]=;
return f[k][i][j][state];
}
//the ith number isn't used
int res=tryit(k,i+,j,);
//the ith number is used
if (check[i][j])
{
if (state==||(i==j)) res=(res+tryit(k,i,j+,state))%modp;
else if (k>) res=(res+tryit(k-,i,j+,))%modp;
}
f[k][i][j][state]=res;
return res;
}
public:
int getNumber(vector <int> P, int K)
{
n=P.size(),k=K;
for (int i=;i<=n;i++) p[i]=P[i-];
memset(check,true,sizeof(check));
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
for (int t=min(i,j);t<=i||t<=j;t++)
if (p[t]>p[i]) check[i][j]=false;
memset(f,,sizeof(f));
memset(vis,false,sizeof(vis));
return tryit(k,,,);
}
};
Topcoder SRM 605 div1 题解的更多相关文章
- TopCoder SRM 605 DIV1
604的题解还没有写出来呢.先上605的. 代码去practice房间找. 说思路. A: 贪心,对于每个类型的正值求和,如果没有正值就取最大值,按着求出的值排序,枚举选多少个类型. B: 很明显是d ...
- Topcoder SRM 602 div1题解
打卡- Easy(250pts): 题目大意:rating2200及以上和2200以下的颜色是不一样的(我就是属于那个颜色比较菜的),有个人初始rating为X,然后每一场比赛他的rating如果增加 ...
- Topcoder SRM 607 div1题解
好久没来写了,继续继续... Easy(250pts): //前方请注意,样例中带有zyz,高能预警... 题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值.数 ...
- Topcoder SRM 608 div1 题解
Easy(300pts): 题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限.现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需 ...
- Topcoder SRM 606 div1题解
打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...
- Topcoder SRM 604 div1题解
CTSC考完跑了过来日常TC--- Easy(250pts): 题目大意:有个机器人,一开始的位置在(0,0),第k个回合可以向四个方向移动3^k的距离(不能不动),问是否可以到达(x,y),数据满足 ...
- Topcoder SRM 603 div1题解
昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...
- Topcoder SRM 601 div1题解
日常TC计划- Easy(250pts): 题目大意:有n个篮子,每个篮子有若干个苹果和橘子,先任取一个正整数x,然后从每个篮子中选出x个水果,把nx个水果放在一起,输出一共有多少种不同的组成方案.其 ...
- Topcoder SRM 600 div1题解
日常TC计划正式启动! Easy(250pts): 题目大意:给你一个集合,里面一堆数,初始数为0,给你一个目标数,你可以选择集合中若干个数进行OR操作来得到目标数.问至少删去多少个数,使得你永远无法 ...
随机推荐
- MAC下MySQL初始密码忘记修改初始密码
解决MAC下MySQL忘记初始密码的方法分享给大家,供大家参考,具体内容如下 第一步: 点击系统偏好设置->最下边点MySQL,在弹出页面中,点击stop MySQL Servier,输入密码关 ...
- 字符串的输入问题 C++
C++中,初学时最常用的输入字符的方式为cin,但是,cin是如何确定已经完成了字符串的输入了呢?由于不能通过键盘输入空字符("\0"),因此cin需要用别的方法来确定字符串的结尾 ...
- ABAP自定义截取字符串长度函数
SAP 中strlen()只能计算字符串的个数,不能计算含有中文字符串的长度,如字符串“SAP大波霸”,strlen('SAP大波霸') = 6,其实真实长度为3+3*2 = 9.我们可以通过cl_a ...
- Json的用处一
今天,我们用到了json的的用处,其实也就是一个很简单的用处,就是点击一个按钮,触发一个事件,然后调用json, 之后我们就可以进行异步操作,其实只是针对于后台的操作,其实我们并没有对数据库进行刷新, ...
- python 10月30日复习
1.把一个数字的list从小到大排序,然后写入文件,然后从文件中读取出来文件内容,然后反序,在追加到文件的下一行中 import codecs list1 = [2,23,8,54,86,12] li ...
- laravel5.5中间件
目录 1. 中间件知识 1. artisan 命令 2. 文件内容 3. 前置中间件和后置中间件 4. 使用中间件 2. 控制器中间件 1. 中间件知识 1. artisan 命令 php artis ...
- Mongoid Paging and Iterating Over Large Collections
遍历数据库中的所有记录时,我们首先想到的是Model.all.each.但是,当数据量很大的时候(数万?),这就不怎么合适了,因为Model.all.each会一次性加载所有记录,并将其实例化成 Mo ...
- Xcode坑之一Invalid argument
Xcode坑之一Invalid argument 正在搞代码,运行程序时突然发现程序不能再次运行了,一运行就提示Invalid argument 然后FQ各种查啊,试了好多方法都不行,重启,重置,我用 ...
- .swp文件的恢复
.swp 编辑文件的过程中会出现这个隐藏文件. 文件如果正常保存,.swp就会自动删除.如果不正常退出,比如关机,.swp就会留下来. linux下: ls -all 可以查看隐藏文件 命令: vi ...
- Python 3基础教程11-如何利用pip命令安装包和模块
本文介绍如何利用pip命令安装Python相关的包和模块.在Python中有些方法或者模块是自带的功能,也叫(build-in),内构函数,实际使用,可能内构函数或者模块不能完成我们的任务,我们就需要 ...