You Are Given Some Letters...(CodeForces-1202F)(数论分块,思维题)

题目

CF
在这里插入图片描述
注意最后一个周期可以不是满的,其实说最小有点不严谨
1 ≤ a , b ≤ 1 0 9 1\le a,b\le 10^9 1a,b109

思路

首先我们思考一个比较暴力的做法,枚举周期 k k k ,我们记 a + b = n a+b=n a+b=n
我们假设一个周期内 A A A 的数量为 x x x B B B 的数量为 y y y,我们可以得到:
{ 0 ≤ a − ⌊ n k ⌋ ∗ x ≤ x 0 ≤ b − ⌊ n k ⌋ ∗ y ≤ y \begin{cases} 0\le a-\lfloor \frac{n}{k}\rfloor*x\le x\\ 0\le b-\lfloor \frac{n}{k}\rfloor*y\le y \end{cases} {0aknxx0bknyy
我们可以得到
{ a ⌊ n k ⌋ + 1 ≤ x ≤ a ⌊ n k ⌋ b ⌊ n k ⌋ + 1 ≤ y ≤ b ⌊ n k ⌋ \begin{cases} \frac{a}{\lfloor \frac{n}{k}\rfloor+1}\le x\le \frac{a}{\lfloor \frac{n}{k}\rfloor}\\ \frac{b}{\lfloor \frac{n}{k}\rfloor+1}\le y\le \frac{b}{\lfloor \frac{n}{k}\rfloor} \end{cases} {kn+1axknakn+1byknb
因为 x , y x,y x,y 均为整数,我们又可以写为:
{ ⌈ a ⌊ n k ⌋ + 1 ⌉ ≤ x ≤ ⌊ a ⌊ n k ⌋ ⌋ ⌈ b ⌊ n k ⌋ + 1 ⌉ ≤ y ≤ ⌊ b ⌊ n k ⌋ ⌋ \begin{cases} \lceil\frac{a}{\lfloor \frac{n}{k}\rfloor+1}\rceil\le x\le \lfloor\frac{a}{\lfloor \frac{n}{k}\rfloor}\rfloor\\ \lceil\frac{b}{\lfloor \frac{n}{k}\rfloor+1}\rceil\le y\le \lfloor\frac{b}{\lfloor \frac{n}{k}\rfloor}\rfloor \end{cases} {kn+1axknakn+1byknb
看到这个我们就想到了数论分块,因为 ⌊ n k ⌋ \lfloor \frac{n}{k}\rfloor kn 最多只有 2 n 2\sqrt n 2n 个取值,枚举 t = ⌊ n k ⌋ t=\lfloor \frac{n}{k}\rfloor t=kn 得到 k k k 的取值 [ l , r ] [l,r] [l,r]
我们可以得到:
{ ⌈ a t + 1 ⌉ ≤ x ≤ ⌊ a t ⌋ ⌈ b t + 1 ⌉ ≤ y ≤ ⌊ b t ⌋ \begin{cases} \lceil\frac{a}{t+1}\rceil\le x\le \lfloor\frac{a}{t}\rfloor\\ \lceil\frac{b}{t+1}\rceil\le y\le \lfloor\frac{b}{t}\rfloor \end{cases} {t+1axtat+1bytb
{ x ∈ [ ⌈ a t + 1 ⌉ , ⌊ a t ⌋ ] y ∈ [ ⌈ b t + 1 ⌉ , ⌊ b t ⌋ ] \begin{cases} x\in[\lceil\frac{a}{t+1}\rceil, \lfloor\frac{a}{t}\rfloor]\\ y\in[\lceil\frac{b}{t+1}\rceil, \lfloor\frac{b}{t}\rfloor] \end{cases} {x[t+1a,ta]y[t+1b,tb]
此时 x + y = k x+y=k x+y=k k ∈ [ l , r ] k\in[l,r] k[l,r]
于是 k ∈ [ ⌈ a t + 1 ⌉ + ⌈ b t + 1 ⌉ , ⌊ a t ⌋ + ⌊ b t ⌋ ] k\in[\lceil\frac{a}{t+1}\rceil+\lceil\frac{b}{t+1}\rceil,\lfloor\frac{a}{t}\rfloor+\lfloor\frac{b}{t}\rfloor] k[t+1a+t+1b,ta+tb]
于是满足区间合法的情况下求交即是对答案的贡献
注意数论分块写法

代码

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return f*x;
}
#define MAXN 1000000000
#define INF 0x3f3f3f3f
int main(){
	int a=read(),b=read(),n=a+b,ans=0;
	for(int l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		int t=n/l,al=(a+t)/(1+t),ar=a/t,bl=(b+t)/(1+t),br=b/t;
		if(al<=ar&&bl<=br) ans+=max(0,min(r,ar+br)-max(l,al+bl)+1);
	}
	printf("%d\n",ans);
    return 0;
}

后记

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值