Codeforces Round #641 (Div. 2)
Codeforces Round #641 (Div. 2)
A
题意
定义 表示 的最小非一因子
给出 次操作,每次计算 的值,并令
求经过 次操作后的答案
思路
显然如果 是偶数,最小因子是2
偶数加偶数不会改变奇偶性,所以最后答案就是
如果 是奇数,如果最小因子是一定是奇数
奇数加奇数改变奇偶性,划归到偶数情况
因此只要先暴力把 变成偶数,再加上剩余次数乘2即可
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N,K;
cin >> N >> K;
int ans = N;
while(K --) {
int r = 0;
for(int i = 2;i <= ans / i;i ++) {
if(ans % i == 0) {
r = i;
break;
}
}
if(!r) r = ans;
ans = ans + r;
if(ans % 2 == 0) break;
}
ans += K * 2 ;
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}
B
题意
给 个数字分配权值 ,现在要从这个序列中选出满足如下要求的最长序列,输出其长度
定义漂亮序列:
序列中任意的数字 整除 ,即
且它们的权值 构成的序列严格递增
思路
显然最坏长度为1
为了保证 的单调性,可以将数字按照它们的权值排序
问题转为,在一个前缀中选择最长序列的问题
我们可以枚举以第 个数字为序列结尾的情况
再枚举 的所有因子,看这个因子是否在这个序列中存在
如果存在,继续以这个因子为结尾向前枚举
单纯向前搜索显然超时,所以在搜索过程中加入记忆化即可
PS:排序时,如果权值相等,为保证权值的严格递增,需要将数字按照降序排列
PS2:如果不加记忆化,不仅时间复杂度不接受,正确性也是不能保证的,因为搜索时忽略前缀的顺序的,比如3,2,1,4 就很有可能出现 的搜索链,所以在搜索时还应该记录因子具体出现的位置。但因为加上了记忆化,前缀都是被搜索过的合法情况,就不用再在意这些,只要第一次搜索合法之后返回的都是合法的答案。
所以本题更加简便的写法应该是DP,这里就不写了
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N;
cin >> N;
vector<int> s(N + 1);
vector<int> ids(N + 1);
for(int i = 1;i <= N;i ++) {
cin >> s[i];
ids[i] = i;
}
sort(ids.begin() + 1,ids.end(),[&](int a,int b) {
if(s[a] != s[b]) return s[a] < s[b];
return a > b;
});
vector<bool> st(N + 1);
vector<int> f(N + 1,-1);
function<int(int)> dfs = [&](int x) {
if(f[x] != -1) return f[x];
if(x == 1) {
return (int)(st[x]);
}
vector<int> d;
d.push_back(1);
int ans = 1;
for(int i = 2;i <= x / i;i ++) {
if(x % i == 0) {
d.push_back(i);
if(i * i != x) {
d.push_back(x / i);
}
}
}
for(int i = 0;i < d.size();i ++) {
if(st[d[i]]) ans = max(ans,1 + dfs(d[i]));
}
return f[x] = ans;
};
int ans = 1;
for(int i = 1;i <= N;i ++) {
int cur = ids[i];
st[cur] = 1;
ans = max(ans,dfs(cur));
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}
C
题意
求一个序列所有子串的 的
思路
最暴力的解法就是枚举坐端点,枚举右端点计算
现在考虑如何优化掉对右端点枚举
设对枚举到的左端点 ,它之后的后缀都会对答案有贡献
可表示为
可以发现,对任意的 ,它们都有公因子
实际上是对数字的每个质因子的幂次取 的操作
则是对每个质因子的幂次取 的操作
因为区间 的可以拆成两个数的 ,所以可直接分析只有三个数的情况
从质因子的视角下看这个式子
设任意一个质因为 , 的指数为 , 的指数为 , 的指数为 ,对每一个质因子,上式变为
因此有
之后每个 再取个 就是答案
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N;
cin >> N;
vector<int> a(N + 1);
for(int i = 1;i <= N;i ++) {
cin >> a[i];
}
vector<int> g(N + 1);
g[N] = a[N];
for(int i = N - 1;i > 0;i --) {
g[i] = __gcd(g[i + 1],a[i]);
}
int ans = 0;
for(int i = 1;i < N;i ++) {
ans = __gcd(ans,g[i + 1] * a[i] / __gcd(a[i],g[i + 1]));
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
//int T;cin>>T;
//while(T--)
solve();
return 0;
}
知乎上有更加对这个式子更详细的证明 怎么证明GCD(a,LCM(b,c))=LCM(GCD(a,b),GCD(a,c))? - 知乎 (zhihu.com)
D
题意
对一个序列进行区间操作
每次可以把一段区间变成这个区间第 大的数
问最后是否可以全变成目标数字
思路
显然如果序列中没有 一定不行
按区间长度考虑
如果区间长度为2,如果可以把两个数字变为
之后只要不断选择长度为3的区间,总可以达成目标
我们先把这上述可以达成要求的串叫好串
如果长度为2的区间不行,比如 在 时就是不行的
考虑长度为3的情况
不妨设小于 为 0, 等于 为 1, 大于 为 2
- ,很显然不做讨论
- ,会将 1 变为 0,对答案不利,同理 也是
- 可以化归到长度为2的情况
- 的情况会让一个大数变小数,此时如果这个大数旁边就是一个 就会和这个大数构成好串,对答案来说是不优的
- 的情况可以将小数变成大数,然后不断扩散这个大数,直到遇到第一个 ,之后又会得到一个好串是可行的
- 之后对于 的情况同上分析,核心是通过这样的变换是否可以构成一个好串
对长度大于三的区间,可以发现,总可以用长度为三或者长度为二的序列拼出,本质上和长度为三或二的区间一样。
综上,只要对长度为2和3的区间扫一遍,判断是否有满足条件的情况即可
#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
void solve()
{
int N,K;
cin >> N >> K;
bool ok = 0;
vector<int> a(N + 1);
for(int i = 1;i <= N;i ++) {
cin >> a[i];
ok |= (K == a[i]);
}
if(N == 1) {
if(K == a[1]) {
cout << "yes\n";
}else {
cout << "no\n";
}
return;
}
if(!ok) {
cout << "no\n";
}else {
for(int i = 1;i < N;i ++) {
int x = a[i],y = a[i + 1];
if(x > y) swap(x,y);
if(x == K) {
cout << "yes\n";
return;
}
}
for(int i = 1;i < N - 1;i ++) {
vector<int> t;
for(int j = i;j < 3 + i;j ++) {
t.push_back(a[j]);
}
sort(t.begin(),t.end());
if(t[1] >= K && t[2] >= K) {
cout << "yes\n";
return;
}
}
cout << "no\n";
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T;cin>>T;
while(T--)
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异