日常TC计划~

Easy(250pts):

题目大意:有n个篮子,每个篮子有若干个苹果和橘子,先任取一个正整数x,然后从每个篮子中选出x个水果,把nx个水果放在一起,输出一共有多少种不同的组成方案。其中n<=50,每个篮子中每种水果的个数<=1000000,可能有篮子不存在水果。

首先考虑x的大小,由于每个篮子中都要取出x个水果,那么apple[i]+orange[i]>=x,于是我们先将所有的篮子扫一遍,得到x的上届。

接下来我们枚举x,考虑每一个篮子中的情况,

由于最后要求的是方案数,所以我们只需要关心从每个篮子取出多少个苹果和多少个橘子就可以了。

考虑第i个篮子,那么从这个篮子中最多取出min(apple[i],x)个苹果,最少取出x-min(orange[i],x)个苹果。(因为最多取出min(orange[i],x)个橘子)

于是我们将上届与下届的差全部加在一起,然后直接统计答案就可以了。

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

 #include <bits/stdc++.h>
using namespace std;
class WinterAndPresents
{
public:
long long getNumber(vector<int> apple,vector<int> orange)
{
int n=apple.size();
int mn=;
for (int i=;i<n;i++) mn=min(mn,apple[i]+orange[i]);
long long ans=;
for (int k=;k<=mn;k++)
{
int cnt1=,cnt2=;
//cnt1 means the least of apples should be taken
//cnt2 means the most of apples should be taken
for (int i=;i<n;i++)
{
cnt1+=k-min(k,orange[i]);
cnt2+=min(k,apple[i]);
}
ans+=cnt2-cnt1+;
}
return ans;
}
};

Medium(500pts):

题目大意:给定两个正整数N,M,现在有两个集合{1,2...N}{1,2...M},对于这两个集合分别选择一个子集(可以为空),使得这两个子集没有交集并且前一个子集所有数XOR的值小于后一个子集所有数XOR的值,其中N,M<=2000。

一眼就知道这应该是一个数位DP吧~~~

我们考虑f[i][j][k]表示当前考虑是否选择数字i,前一个子集的xor值为j,后一个子集的xor值为k,

于是我们得到f[i][j][k]=f[i+1][j^i][k]+f[i+1][j][k^i]+f[i+1][j][k],

这样做的话时间复杂度O(n^3),然而n范围有2000,显然会超时。

我们考虑两个数X和Y,如果X小于Y,那么X一定在某一个二进制位小于Y,而之前几位全部相同。

于是我们发现X XOR Y前几位都是0,某一位为1,

这样我们只需要统计一下X哪一个二进制位比Y小,然后在转移的时候纪录一下A的那一个二进制位就可以了。

设f[i][j][k]表示当前考虑是否选择数字i,目前两个子集的XOR值为j,第一个子集的第i为为k。

于是我们得到f[i][j][k]=f[i+1][j][k]+f[i+1][j^(i>>pos)][k^((i>>pos)&1)]+f[i+1][j^(i>>pos)][k],

时间复杂度O(n^2logn),

感觉时间限制还是很紧,可以选择记忆化搜索,听说是严格O(n^2)的然而我不会证明。

代码如下:

 #include <bits/stdc++.h>
#define modp 1000000007
#define Maxn 2057
int f[Maxn][Maxn][];
bool flag[Maxn][Maxn][];
using namespace std;
int n,m;
class WinterAndSnowmen
{
int tryit(int pos,int Min_num,int now1,int now2)
{
//Min_num means the min number you can choose
//now1 means the xor of the numbers in the set A xor with the xor of the numbers in the set B
//now2 means the ith position of the xor of the numbers in the set A
//pos means i
if (flag[Min_num][now1][now2]) return f[Min_num][now1][now2];
flag[Min_num][now1][now2]=true;
if (Min_num==)
{
if (now1==&&now2==) f[Min_num][now1][now2]=; else f[Min_num][now1][now2]=;
return f[Min_num][now1][now2];
}
f[Min_num][now1][now2]=tryit(pos,Min_num-,now1,now2);
if (Min_num<=n) f[Min_num][now1][now2]=(f[Min_num][now1][now2]+tryit(pos,Min_num-,now1^(Min_num>>pos),now2^((Min_num>>pos)%==)))%modp;
if (Min_num<=m) f[Min_num][now1][now2]=(f[Min_num][now1][now2]+tryit(pos,Min_num-,now1^(Min_num>>pos),now2))%modp;
return f[Min_num][now1][now2];
}
public:
int getNumber (int N,int M)
{
n=N,m=M;
int ans=;
for (int i=;i<=;i++)
{
memset(f,,sizeof(f));
memset(flag,false,sizeof(flag));
ans=(ans+tryit(i,max(n,m),,))%modp;
}
return ans;
}
};

Hard(950pts):

题目大意:给你n个商店信息,每个店告诉你开门时间,红绿蓝的小球个数,每个商店每天只能卖一个小球,数据爆炸同一天最多只有两个商店开门,如果有两个商店,那么这两个商店必须卖同样颜色的小球,求总的方案数。其中n<=50,一个点一种颜色的小球<=100,任何的时间<=500。

也挺显然的是一道DP吧~~~

我们考虑f[i][x1][x2][y1][y2]分别表示出时间i的时候两个商店的红绿小球个数分别为x1,x2,y1,y2,

于是我们可以得出两个商店的蓝球个数,

这样就可以直接大力转移了,

时间复杂度O(T*w^4),怎么算都超时吧。。。

我们来考虑如何用更少的数字来描述一个状态,从题目中我们可以发现一个性质,每一个商店开店的时间一定是连续的一段。

我们可以继续考虑记忆化搜索,我们用三个数字来表示一个状态f[i][x1][x2],

其中i表示时间,x1表示当前的商店红球被删除的个数,x2表示当前的商店绿球被删除的个数。

我们来考虑一下对于当前的商店的定义,

如果当前的时刻t,没有商店开门,那么当前商店定义为空,x1和x2都是0。(其实好像定义成多少都没关系)

如果当前的时刻t,恰好有一个商店开门,那么当前的商店定义为这个商店。

如果当前的时刻t,恰好有两个商店开门,那么定义当前的商店为开门较早的那个商店。

于是我们来考虑一下这个函数,我们写成记忆化搜索的形式,

如果当前没有商店开门,直接将时间从t跳到t+1,将x1和x2变成0;

如果当前恰好有一个商店开门,直接将时间从t跳到当前的商店关门的时间,将x1和x2变成0;

如果当前恰好有两个商店开门,

(1)如果当前的两个商店同时关门,那么这两个商店剩余的红绿蓝球个数应该完全一致,直接乘上三者的组合数,然后将时间跳到当前商店关门时间,将x1和x2变成0;

(2)如果当前的两个商店,开门较早的关门较早,那么开门较早的商店剩余的红蓝绿球个数应该完全小于等于另一个商店的个数,直接乘上三者的组合数,然后将时间跳到当前商店关门时间,并且将当前的商店改变成另一个商店,并将x1和x2变成另一个商店的数据;

(3)如果当前的两个商店,开门较早的关门较晚,那么另一个商店的红蓝绿球个数完全小于等于当前商店剩下来的个数,那么直接处理掉另一个商店,乘上三者的组合数,把时间跳到另一个商店的关门时间,处理x1和x2。(分别减掉另一个商店的个数就可以了)

最后来考虑三者的组合数,我们有a个红球,b个蓝球,c个绿球,不同的排列方式一共有C(a+b+c,a)*C(b+c,b),

于是我们可以先预处理出C数组和时间轴,然后dp记忆化搜索就可以了。

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

 #include <bits/stdc++.h>
#define Maxn 57
#define Maxa 107
#define Maxt 507
#define modp 1000000007
using namespace std;
struct data {int l,r,x,y,z;} a[Maxn];
int cover[Maxt][],combination[*Maxa+][*Maxa+];
int f[Maxt+][Maxa][Maxa];
bool flag[Maxt][Maxa][Maxa];
//cover is the data of the two shops in the same day
int n;
class WinterAndShopping
{
int calc(int x,int y,int z)
{
int ans=(1LL*combination[x+y+z][x]*combination[y+z][y])%modp;
return ans;
}
int tryit(int t,int x,int y)
{
//t means the present time
//x means how many red balls have been taken from the shop
//y means how many green balls have been taken from the shop
//if there is only one shop
//we can calculate how many blue balls
//if there is two shops at the same time
//we can also calculate it and skip the time to the next shop
if (flag[t][x][y]) return f[t][x][y];
flag[t][x][y]=true;
int p=cover[t][],q=cover[t][];
if (p<)
{
//there is no shop open at the moment
f[t][x][y]=tryit(t+,,);
return f[t][x][y];
}
int x1=a[p].x-x,y1=a[p].y-y,z1=a[p].z-t+a[p].l+x+y;
//x1 means how many red balls there are in the first shop
//y1 means how many green balls there are in the first shop
//z1 means how many blue balls there are in the first shop
if (q<)
{
//there is exactly one shop open at the moment
if (t==a[p].r)
{
//we should skip the time directly to the next shop
f[t][x][y]=tryit(t+,,);
return f[t][x][y];
} else
{
if (x1) f[t][x][y]=tryit(t+,x+,y);
if (y1) f[t][x][y]=(f[t][x][y]+tryit(t+,x,y+))%modp;
if (z1) f[t][x][y]=(f[t][x][y]+tryit(t+,x,y))%modp;
return f[t][x][y];
}
}
//there is exactly two shops open at the moment
if (a[p].r==a[q].r)
{
//the two shops will be closed at the same time
//then the three kinds of balls should be the same
if (x1==a[q].x&&y1==a[q].y&&z1==a[q].z)
{
f[t][x][y]=(1LL*tryit(a[p].r+,,)*calc(x1,y1,z1))%modp;
}
return f[t][x][y];
} else if (a[p].r<a[q].r)
{
//the first shop will be closed earlier than the second one
//then the three kinds of balls in the first shop should not be more then the second one
if (x1<=a[q].x&&y1<=a[q].y&&z1<=a[q].z)
{
f[t][x][y]=(1LL*tryit(a[p].r+,x1,y1)*calc(x1,y1,z1))%modp;
}
return f[t][x][y];
} else if (a[p].r>a[q].r)
{
//the first shop will be closed later than the second one
//then the three kinds of balls i the first shop should not be less than the second one
if (x1>=a[q].x&&y1>=a[q].y&&z1>=a[q].z)
{
f[t][x][y]=(1LL*tryit(a[q].r+,x+a[q].x,y+a[q].y)*calc(a[q].x,a[q].y,a[q].z))%modp;
}
return f[t][x][y];
}
}
public:
int getNumber(vector<int> first, vector <int> red, vector <int> green, vector <int> blue)
{
n=first.size();
//deal with the data of the combination number
memset(combination,,sizeof(combination));
combination[][]=;
for (int i=;i<=*Maxa;i++)
{
combination[i][]=;
for (int j=;j<=i;j++)
combination[i][j]=(combination[i-][j]+combination[i-][j-])%modp;
}
//deal with the data of the time schedule
for (int i=;i<Maxt;i++) cover[i][]=cover[i][]=-;
for (int i=;i<n;i++)
{
a[i].l=first[i],a[i].x=red[i],a[i].y=green[i],a[i].z=blue[i];
a[i].r=a[i].l+a[i].x+a[i].y+a[i].z-;
for (int j=a[i].l;j<=a[i].r;j++)
{
if (cover[j][]==-) cover[j][]=i; else
{
cover[j][]=i;
if (a[i].l<a[cover[j][]].l) swap(cover[j][],cover[j][]);
}
}
}
memset(f,,sizeof(f));
memset(flag,false,sizeof(flag));
f[Maxt][][]=,flag[Maxt][][]=true;
return tryit(,,);
}
};

打卡完成!

Topcoder SRM 601 div1题解的更多相关文章

  1. Topcoder SRM 602 div1题解

    打卡- Easy(250pts): 题目大意:rating2200及以上和2200以下的颜色是不一样的(我就是属于那个颜色比较菜的),有个人初始rating为X,然后每一场比赛他的rating如果增加 ...

  2. Topcoder SRM 607 div1题解

    好久没来写了,继续继续... Easy(250pts): //前方请注意,样例中带有zyz,高能预警... 题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值.数 ...

  3. Topcoder SRM 608 div1 题解

    Easy(300pts): 题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限.现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需 ...

  4. Topcoder SRM 606 div1题解

    打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...

  5. Topcoder SRM 605 div1 题解

    日常打卡- Easy(250pts): 题目大意:你有n种汉堡包(统统吃掉-),每一种汉堡包有一个type值和一个taste值,你现在要吃掉若干个汉堡包,使得它们taste的总和*(不同的type值的 ...

  6. Topcoder SRM 604 div1题解

    CTSC考完跑了过来日常TC--- Easy(250pts): 题目大意:有个机器人,一开始的位置在(0,0),第k个回合可以向四个方向移动3^k的距离(不能不动),问是否可以到达(x,y),数据满足 ...

  7. Topcoder SRM 603 div1题解

    昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...

  8. Topcoder SRM 600 div1题解

    日常TC计划正式启动! Easy(250pts): 题目大意:给你一个集合,里面一堆数,初始数为0,给你一个目标数,你可以选择集合中若干个数进行OR操作来得到目标数.问至少删去多少个数,使得你永远无法 ...

  9. Topcoder SRM 643 Div1 250<peter_pan>

    Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*... ...

随机推荐

  1. scapy--初识

    常用的包结构: (1)OSI 5层模型 OSI中的层 功能 TCP/IP协议族 应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 传 ...

  2. 使用PHP生成分享图片

    小程序导航 wq.xmaht.top 假设代码中用到的资源文件夹在当前code_png目录下: /** * 分享图片生成 * @param $gData 商品数据,array * @param $co ...

  3. redhat 配置本地yum源

    redhat配置3个源就够了: 1.本地yum源,就是你本地的ISO 2.配置163源 3.配置epel源 环境:redhat7 + vmw 12 pro 1.配置本地yum源 要配置本地源,需要先把 ...

  4. centos安装xfce及输入法

    一.执行CentOS7 最小安装 去官网 https://www.centos.org/ 下载CentOS-7-x86_64-Minimal-1804.iso,然后使用rufus刻录U盘,安装之.安装 ...

  5. ABAP自定义截取字符串长度函数

    SAP 中strlen()只能计算字符串的个数,不能计算含有中文字符串的长度,如字符串“SAP大波霸”,strlen('SAP大波霸') = 6,其实真实长度为3+3*2 = 9.我们可以通过cl_a ...

  6. NumPy库入门

    ndarray数组的元素类型 ndarray数组的创建 ndarray数组的操作 ndarray数组的运算

  7. Python locale 多语言模块和我遇到的坑

    Table of Contents 1. locale遇到的问题 1.1. locale 简介 1.1.1. 什么是locale 1.1.2. locale 相关命令 1.2. Python loca ...

  8. cocos2d-x 3.0环境配置(转)

    cocos2d-x 3.0发布有一段时间了,作为一个初学者,我一直觉得cocos2d-x很坑.每个比较大的版本变动,都会有不一样的项目创建方式,每次的跨度都挺大…… 但是凭心而论,3.0RC版本开始 ...

  9. layout焊盘过孔大小的设计标准

    PCB设计前准备 1.准确无误的原理图.包括完整的原理图文件和网表,带有元件编码的正式的BOM.原理图中所有器件的PCB封装(对于封装库中没有的元件,硬件工程师应提供datasheet或者实物,并指定 ...

  10. HDFS写数据和读数据流程

    HDFS数据存储 HDFS client上传数据到HDFS时,首先,在本地缓存数据,当数据达到一个block大小时.请求NameNode分配一个block. NameNode会把block所在的Dat ...