刷题

刷题

刷那么多题目,如果没有记录就等于白刷,真正弄懂一题,胜过copy十题。刷题记录,不定时更新,大概
转载请注明出处

poj 3169

差分约束 spfa 差分约束组 最短路
笔记:
spfa
跑最短路可以判断是否存在负环和是否连通。但跑一遍spfa只能判断1~n是否连通,而不能判断是否没有负环。
因为当图不连通的时候,只访问了图的一部分,另一部分的负环无法检测。
如果要检测是否存在负环,需要设置一个超级源,跑一边。
这里容易设陷阱,输出存在负环(-1)的级别高于图不连通(-2),如果没有注意到,会掉坑里。
差分约束组建图
求1~n的最大值,小于等于号。
x1-x2<=w 则x1到x2有一条值为w的边,w可为负数
求1~n的最小值,大于等于号。
x1-x2>=w,则x1到x2有一条值为w的边,跑最远路。

题目大意:

有一群牛排队,每只牛有一个编号,牛的排队顺序由编号确定,但在X轴的位置不确定。
比如:1号牛在0点 2号牛在3点,3、4号牛在7点,5号牛在12点……
现在给出一些限制条件:
x  y d1
x和y牛最远距离不超过d1
x y d2
x和y牛最近距离不小于d2
求:
1号牛和N号牛的最远距离
如果不可行 输出-1
如果1号牛和N号牛的距离任意 输出-2
其他:输入可行的最远距离

解题思路:

牛的编号从x1、x2 ……xn从小到大排列
根据x1和x2牛最远距离不超过d1可以写出不等式
x2-x1<=d1
x1-x2<=-d1
设x2到x1的距离为d1,x1到x2的距离为-d1
同理根据x和y牛最近距离不小于d2,可以列出两个距离。得到差分约束组。
利用差分约束求最远(近)解的思路,求得答案。
注意:不可行:出现负环
任意:最大距离为0x3f3f3f3f3f

代码:

https://pastebin.ubuntu.com/p/MV2Pj835Yq/

CodeForces 1295D

最大公因数,欧拉函数,欧拉函数性质,最大公因数性质
笔记:欧拉函数性:

题目大意

给出两个数a,m,求有多少个x,x∈(0,m),满足gcd(a,m)==gcd(a+x,m)

数据范围:0<a<m<=1010

解题思路

题目抽象化,一般化
a<=y<a+m,gcd(y,m)==gcd(a,m)==k 问有多少个y?
根据公约数的性质
1,gcd(y,m)==k,可变为gcd(y/k,m/k)==1
a'=a/k 向上取整
b'=(a+m)/k 向上取整。
y'=y/k,m'=m/k
2,[a,b)中y'的个数gcd(y',m')==1。
3,用m'的质因子去筛选[a,b]中的数,考虑容斥问题。

具体化 0<x<m,
因为gcd(a,b)==gcd(a-b,b) (a>b)
所以gcd(a+x,m)==gcd((a+x)%m,m)==k
此题中的[a,b)也变成了[0,m/k];
即:求[0,m/k]中与m/k互质的数
因此变为了关于欧拉函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0kAUxmae-1614826768248)(https://bkimg.cdn.bcebos.com/formula/ba40ed514646510df8a1033ff30701aa.svg)]

代码:

https://pastebin.ubuntu.com/p/zYS88b4zMs/

Fibonacci again and again

博弈 sg函数 Nim博弈

题目大意:

两个博弈,有三堆石头,每堆不超过1000.
每次只能从一堆中取走斐波那契数的石头
直到不能取的人输。

解题思路:

用sg函数求解

代码:

https://pastebin.ubuntu.com/p/rbRT77yk67/

Gym - 236916C

线段树 维护 区间最大连续和 更新 区间连续和 单点修改 区间输入坑 a,b a>b

题目大意:

每一个点有一个值,一共有[1,n]个点。
每次询问给出a,b 问区间[a,b](或[b,a])中最长的连续和

做法:

难点在于维护线段树每个节点的区间最大连续和
node {
	sum:区间长度
	llagre:包含左端点的最大连续和
	rlagre:包含右端点的最大连续和
	large:区间的最大连续和
	lt,rt:左右子树
}
更新:
区间最大值lagre=max(lt.large/*左子树最大值*/,rt.large/*右子树最大值*/,lt.rlagre+rl.large/*包含区间中点的最大值*/)
区间左端点最大值llarge=max(lt.llarge/*左子树左端点最大值*/,lt.sum+rt.llagre/*左端点最大值包含区间中点*/)
 区间右端点最大值llarge=max(rt.rlarge/*右子树右端点最大值*/,rt.sum+lt.rlagre/*右端点最大值包含区间中点*/)
 查询:
 查询的时候,每次利用到的lt,rt的信息不知一个,所以返回的不是数值,而是返回一个节点。沿用更新

代码

Ubuntu Pastebin

LibreOJ - 2130

树链剖分 dfs序 树结点值动态改变 

题目大意

给一棵树数结点值只有0,1,有两种操作,
第一种,加:给一个结点,把从根到该结点的所有结点变为1,问变了多少个结点
第二种,减:给一个结点,把该节点到这棵树的叶子之间的结点全部变为0,问变了多少个结点。

解题思路

用树链剖分,操作包裹两种
第一种加:从根结点到选定结点的一条链上全部置为1, 树链剖分完成
第二种减,选定结点的所有子数结点全部置为0,同时先查询1的个数,dfs 子树在同一段区间内

代码

https://pastebin.ubuntu.com/p/4MypCP9Yj4/

树剖大毒瘤 150行调bug一小时

CodeForces - 983A

二进制 多进制 进制转换 分数 gcd 最大公约数 互质 无限小数 用gcd 求质因数 a的质因数是否是b的质因数 两个数拥有相同质因子

题目大意

给出一个分数a/b 问是否可以被k进制在有限位表示
比如1/3 不能在10进制中表示infinity
1/4呢一在10进制中表示finity

解题思路

根据进制小数转换方式

a/b=x1/21+x2/22+x3/23……+xn/2n:如果a/b可以被表示则可以找到这些x。
思考一下,也就是1/b 可以被表示,a 是什么无关紧要。只要不是0(0一定能被表示)
在对右边通分一下变成了:1/b=(y1+y2+y3……+yn)/2n,转换一下:b=(2n)/(y1+y2+y3……+yn),所以2n是b倍数,那么只要找到这个2n就解决了,或者判定这个2n是否存在就可以了
举例思考:如果b是3 就不能存在2n满足是3的倍数 ,但可以存在6n是3的倍数 ,b是25,则10n可以是b的倍数:

b=5X5 而10n=(2X5)n,只要n=2,就会有两个因子5,所以b可以被表示

思路1:

只要b的所有质因子是进制k的因子。代码:前面约分省略。

int ans=1;//判断是否满足
for(ll i=2;i*i<=b;i++){//枚举i,直到为质因数
    if(b%i==0){//找到b的质因子
        if(k%i!=0){//不是k的质因子
            ans=0;break;
        }
        while(b%i==0)b/=i;//降低接下来搜索范围
    }
}
if(b>1&&k%b!=0){ans=0;}//补一刀

卡在了test 10,超时了。

思路2:

优化:不去枚举i,先预处理所有的质数,得出质数数组prime[],但只枚举1~2e5+10以内的字数,因为所给的1018太大了。

int ans=1;//判断是否满足
for(int i=0;i<cnt&&prime[i]<=b;i++){//枚举质因子
    if(b%prime[i]==0){//找到b的质因子
        if(k%prime[i]!=0){//不是k的质因子
            ans=0;break;
        }
        while(b%prime[i]==0)b/=prime[i];
    }
}
if(b>1&&(k%b!=0)){ans=0;}//补一刀

也卡在了test 10 ,超时,又翻车了。

思路3

优化:之后选着了去做别的题,第三,四题,转换思路,做完之后,灵光一闪,可不可以用gcd求出k和b的最大公约数,每次用b除以他,直到b除到1(满足)或者公约数为1,不唯一(不满足)

k=-1;
while(k!=1&&b!=1){//直到b除到1(满足)或者公约数为1,不唯一(不满足)
    k=gcd(max(b,c),min(b,c));
    b/=k;
}
if(b==1)……

卡在了test 13 晕死了。决定去看答案

思路4

答案和我最后的思路是一样的,但又进一步优化了

k=-1;
while(b!=1){//直到b除到1(满足)或者公约数为1,不唯一(不满足)
    k=gcd(max(b,c),min(b,c));
    if(k==1)break;//当为k==1的时候,为了防止下面进入死循环,先推出
    while(b%k==0)b/=k;//一次去掉多组一样的质因子
}
if(b==1)……

终于过了

完整代码:

https://pastebin.ubuntu.com/p/TCKF5D6Nmg/

CodeForces - 962B

排座位 简单思维题

题目大意

又一串座位***...*...
*:已经有人坐了 .:没有人坐。现在有a,b两组人,分别有a,b个。同组人座位不能相邻,问可以坐下人(a+b)有多少?

解题思路

三种情况
*.*:一个座位连续x,应该让人数多的组坐这个位置,为了防止后面人数:3a4b *.*...... :*a*abab.b不如*b*ababab好
*..*:两个座位连续xy:怎么放都一样
*...*:三个座位连续xyx:其实变成了第一种情况,让多的人当x

分析直到a和b其实互换名称。只要将多的命名为a,那么久可以简化代码量。

代码:

https://pastebin.ubuntu.com/p/T5W58JwWWY/

WA4发原因

ans没有初始化,在本机调试的时候竟然得出了正确答案,导致卡了好久,心疼。习惯不好,定义时一定要初始化提醒自己

CodeForces - 962C

贪心 排列组合 平方数 广度搜索。平方数判定

题目大意

给出一个数2X10^9以内(保证无前导零),每次删掉一个数,称为一次操作。要把这个数变成一个平方数比如25,625,问最少要经过多少次操作
比如:数10025 答案为2 10025-->1005-->100

解题思路

第一种
枚举所有平方数,用平方数去测试是不是在所给的数的可能通过某种方式达到。
复杂度10^5*(分解和比对的时间)sqrt(10^9)≈10^5
第二种
根据所给的数,分解后重构,枚举所有操作,第一次9种不同的操作,第二次8种……
复杂度10!*(分解和重组的时间)==3628800*(分解和重组的时间)

现在分析,好像第一种更快,比赛的我选择了第二种,绝对是脑抽了,但还好过来:用广度搜索做。

第二种ac代码

https://pastebin.ubuntu.com/p/JPNsrNRxfw/

WA了一发

原因判断是否是平方数的时候

float sq=sqrt(now);
if(sq-(int)sq==0){//是平方数}//应该是那里了的浮点误差导致了WA
修改后:
ll sq=sqrt(now);
if(sq*sq==now){}//这么做避免了浮点误差,然后就过了

CodeForces - 962D

构造 1248游戏变化 思维 map数据结构

题目大意

给出一组数[3,4,1,2,2,1,1],当出现两个相同的数字的时候,左边的去掉,右边变成两倍,问最后剩下的数组是什么样的。
 [3,4,1,2,2,1,1] → [3,4,2,2,2,1] → [3,4,4,2,1] → [3,8,2,1].
 n<150000, 1<=ai<10^9

解题思路

如果每次寻找一组,肯定会超时,而且 2 1 1 可以变为 2 2 ->4,像是消去游戏一样
定义一个数组num[maxn],记录所有输入的数据,然后用个map[num[i]]=tp,记录之前未出现过的数字,如果当前数字的map已经被填了,那么就说明有两个相同的数字,更新:
循环查看mp[num[i]]直到不再出现
num[mp[num[i]]]=0(删掉前面的数),map[num[i]]=0(num[i]消去出现证明);num[i]*=2(num[i]翻倍);
不再出现之后
mp[num[i]]=i(记录新出现的数)
复杂度O(n*ln(k))

代码:

https://pastebin.ubuntu.com/p/v9BPt5ksPs/

E - Create The Teams

思维 组合 构造

题目大意

有n个人组队,每一个人有一个价值x,求可能的最大队伍数(队伍人数不能为0)
队伍满足:队伍人数*队伍所有人中的最小价值xmin<k
给出n k
x1 x2 x3 …… xn

解题思路

如果说某个人的能力值但与k ,他完全可以一个人组队1*x>k
其他人的能力值小于k:从大到小根据价值排列 y1 y2 y3 ……yn
y1*1<k 那么尝试[y1 y2] 2*y2? >k:组队成功 <k:继续拉下一个人 3*y
组队成功之后队伍人数变为0 从下一个数开始组队。
这种方式保证了,每次选择不会变劣。

代码:

https://pastebin.ubuntu.com/p/qQ6RM6M2CS/

WA了一发

看错题意,队伍人数 the number of programmers in the team, 把the number【队伍人数】 理解成了 skill number【队伍每个人的能力者。】
英语不行

为0)
队伍满足:队伍人数*队伍所有人中的最小价值xmin<k
给出n k
x1 x2 x3 …… xn


### 解题思路

如果说某个人的能力值但与k ,他完全可以一个人组队1x>k
其他人的能力值小于k:从大到小根据价值排列 y1 y2 y3 ……yn
y1
1<k 那么尝试[y1 y2] 2y2? >k:组队成功 <k:继续拉下一个人 3y
组队成功之后队伍人数变为0 从下一个数开始组队。
这种方式保证了,每次选择不会变劣。


### 代码:

https://pastebin.ubuntu.com/p/qQ6RM6M2CS/

### WA了一发

看错题意,队伍人数 the number of programmers in the team, 把the number【队伍人数】 理解成了 skill number【队伍每个人的能力者。】
英语不行 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值