日常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. 中通快递股份有限公司.net高级面试题

    中通快递分布式技术开发   gc垃圾回收原理 .net中,托管代码的内存管理是自动的,由GC进行管理,而对于非托管代码,则需要.net手动处理 CLR运行时,内存分为:托管堆和栈,其中栈用于存储值类型 ...

  2. Git版本控制使用方法入门教程

    1. 概述 对于软件版本管理工具,酷讯决定摒弃CVS而转向Git了. 为什么要选择Git? 你真正学会使用Git时, 你就会觉得这个问题的回答是非常自然的.然而当真正需要用文字来回答时,却觉得文字好像 ...

  3. The Extinction of Some Languages【一些语言的消失】

    The Extinction of Some Languages Languages have been coming and going for thousands of years, 语言的产生和 ...

  4. Dialog BLE 学习之 修改分散加载文件 (2)

    最近搞Dialog的BLE SDK,发现空间不够了,询问原厂,得知可以通过调整分散加载文件而增加空间,一方面是有42KB+8KB的硬件基础,另一方面是原有的程序限制为38KB+8KB.故顺便学习了下把 ...

  5. Python 文本挖掘:使用情感词典进行情感分析(算法及程序设计)

    出处:http://www.ithao123.cn/content-242299.html 情感分析就是分析一句话说得是很主观还是客观描述,分析这句话表达的是积极的情绪还是消极的情绪.   原理 比如 ...

  6. 0x01.被动信息收集

    被动信息收集 基于公开渠道,不与目标系统产生直接交互,尽量避免留下痕迹(不进行大量扫描,正常交互范围) 信息收集内容 IP段 域名 邮件地址(定位邮件服务器,分为个人搭建和公网邮件系统) 文档图片数据 ...

  7. startActivityForResult 请求码不正确

    今天遇到一个坑,就是 startActivityForResult 接收不到正确的请求码. 比如,我startActivityForResult的时候,设置的请求码是4,但是接收到的时候是100032 ...

  8. 怎么用 copy 关键字?

    NSString.NSArray.NSDictionary等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString.NSMutableArray.NSMutableDic ...

  9. 玩转Node.js(三)

    玩转Node.js(三) 上一节对于Nodejs的HTTP服务进行了较为详细的解析,而且也学会了将代码进行模块化,模块化以后每个功能都在单独的文件中,有利于代码的维护.接下来,我们要想想如何处理不同的 ...

  10. 基于Xtrabackup备份集来恢复某个误删除的表(drop)

      Preface       Yesterday,I've demonstratated how to rescue a droped and a truncated table based on ...