昨晚的晚训调bug调到死终于过样例了结果一直wa2,心累
今天上午补补题,下午坐下字典树的题。
早上
先把昨天晚训的c题调完吧
Gym_102220B Balanced Diet(stl+枚举)
题目大意
现有n个糖分别属于m种糖的类型,每个糖有一个甜度值和类型值。
我们现在来取糖,对于第i种糖,如果要选取,那么至少要拿l[i]颗这种类型的糖
S表示我们选取的所有糖的甜度值和,C表示每种类型选取糖的数量的最大值,
比如第一种选2颗,第二种选3颗,第三种选2颗,那么C为3
问S/C的最大值(S和C的gcd为1)
题目思路
因为C是类型数量的最大值,所以我们可以枚举C,从1开始到max(l[i])
如果我们能让所有种类都拿C个,一定是最优的。
我们对于每个种类的糖放在一起并且种类里面从大到小排序。
因为一定要大于l[i]才能拿
所以我们先把每个种类的前l[i]个糖的和求出来
然后枚举C,每次判断这个种类能不能拿,这种糖有没有C个,并且记录对应的S
最后维护答案就好了。
这题刚开始看觉得好麻烦,条件很多,左右不能顾全。
后来才注意到C是种类数量的最大值。
枚举之后,写了好多bug,调完发现wa2,又不知道哪里错了,心态崩了都。
看了别人的解法都是vector,而我是用数组加map。。。
好像说用数组会t
重新改了写法之后,稍稍调了个bug,就过了。。。 麻了
Codeforces Global Round 14 D. Phoenix and Socks
题目大意
有n只袜子(n一定为偶数),前l只为左袜子,后r只为右袜子。
每种袜子有一种颜色。
我们每次可以对一只袜子做一下一种操作
1、左袜子变右袜子
2、右袜子变左袜子
3、将袜子颜色调换成任意颜色
问将所有袜子两两配对(颜色相同的左右袜子)的最小操作数是多少
题目思路
我们首先分类讨论将两个不同情况的袜子配对需要几个操作
1、颜色相同、左右:这时直接配对,操作数为0
2、颜色不同、左右:变换一只颜色即可,操作数为1
3、颜色相同、同左或同右:变换一只形状即可,操作数为1
4、颜色不同、同左或同右:变换一只形状然后变换一只颜色,操作数为2
对于2、3两种情况 2的优先级应该是要高于3的,因为做3操作可能会导致更多的4操作出现
我们看下面这个例子:左:1、1 右:2、3、4、5
如果我们将1、1配对后那们右袜子里面我们要做两次4操作,最后操作数为5
而如果我们将1、1和2、3配对,最后操作数为4
所以我们的贪心策略就很清楚了。
首先先将能够配对的剔除。
然后尽量做2操作。
当只剩下左或右袜子时,我们在遍历颜色,存在颜色相同的袜子时,做3操作。
剩余袜子做4操作。
其实这题分析情况,整理思路没花多久时间。但是一直wa3的第375个数据,人都wa傻了。
看了别人的思路跟我基本也一样,最后那人家代码来对拍,发现是删已配对的数据的时候少删了东西。。。。找了一上午这bug ,吐了。
下午
开始做字典树的题了
Shortest Prefixes POJ - 2001
题目大意
给出许多字符串,求每个字符串的独有的最短前缀
题目思路
字典树板子题,建树的时候tag记录每个位置经过次数
最后找的时候tag=1说明只有这个串经过,所以退出,如果没有就输出全部
该板子还改了好久,总是出些傻逼bug
需要注意的是tag的修改要在u=a[u][c];后面
因为字典树最开始的结点是空的,我们可以把之后每个结点看作对应的字母
void inserts(char *s,int len)
{
int u=1;
for(int j=0;j<len;j++)
{
int c=s[j]-'a';
if(!a[u][c])a[u][c]=++cnt;
u=a[u][c];
tag[u]++;
}
}
统计难题 HDU - 1251
题目大意
给出许多字符串作为字典,以空行为结尾。
又给出字符串,问字典中有多少串的前缀是该字符串
题目思路
思路跟上题基本一样,稍微改改就好了。
这题真的挺坑的,首先没说字典里最多多少字符串,开始一直re
然后以空行结尾也没看着。。。。一直wa
发现之后,又忘记了scanf不读入空格。。。
又找了好久才换成gets过的
Phone List HDU - 1671
题目大意
给出n个字符串,判断自己是否是其他字符串的前缀
题目思路
建树的时候判断路过的点是否是其他字符串的终点,然后到自己终点是判断这个点是不是之前被走过就行了。
计数变量没初始化,re了半个多小时。。。
Xor Sum HDU - 4825
题目大意
给出n个数的集合,然后问集合中的哪个数与数字k的异或值最大
题目思路
这题算是01字典树的模板题
我们将数字的2进制位存入字典树中,在查找时比较2进制位的值,如果相反的值能走就走相反的值,否则走相同的值。因为数字都小于2的32次方,所以我们可以从31位往0位遍历。并且位数越高对数值的大小影响更大,所以从31位往0位遍历更优。
01字典树模板
int a[40*maxn][4];
int tag[40*maxn];
void inserts(int x)
{
int u=0;
for(int j=31;j>=0;j--)
{
int c=(x>>j)&1;
if(!a[u][c])
{
a[u][c]=++cnt;
}
u=a[u][c];
}
tag[u]=x;
}
int finds(int x)
{
int u=0;
for(int j=31;j>=0;j--)
{
int c=(x>>j)&1;
if(a[u][c^1])
u=a[u][c^1];
else
u=a[u][c];
}
return tag[u];
}
晚上
洛谷P4551 最长异或路径
题目大意
给你一棵带边权的树,任意两点间的边值的异或和叫做这两个点的异或路径值,问最大异或路径值是多少
题目思路
这题乍一看还挺头疼得,不知道咋往01字典树上靠。
我们假设t(u,v)表示点u到点v的异或路径值
那么根据异或的性质可以得到下面的转换
t(u,v)=t(u,lca)^t(lca,v) = t(u,lca)^t(lca,root) ^ t(root,lca)^t(lca,v)=t(u,root) ^t(root,v)
所以任意两点之间的异或路径值其实就是两点到根的异或路径值异或后的结果。
那么我们就可以枚举所有点到根的异或路径值,把这些值放入01字典树中。
最后再枚举每个值,与01字典树做查询操作,找到自己的最大值后,更新答案。
这题一开始题目都没读明白就在想这么做了,一脸懵逼的想着怎么把每条边的值放到字典树里面然后比较。。