专栏文章
CF2154C
CF2154C1题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @ming94wc
- 此快照首次捕获于
- 2025/12/02 01:55 3 个月前
- 此快照最后确认于
- 2025/12/02 01:55 3 个月前
你说得对。但是无论什么代价都在所不惜。(题目名字)
题面
有一个长度为 的序列 ,对于每个位置 ,对其进行 操作的代价是 。求最小的代价,使得序列 中存在不互质的两个数。
对于这一题的简单版:。
对于这一题的困难版:。
题解
妙妙贪心思维题,从简单版开始想。
首先,特判本来已有一对不互质的数的情况。具体地,对于每个 对其分解质因数,然后开个桶 存质数 是否存在于 中, 则 存在。若重复覆盖到一个点,则输出 。
接着,对数列的性质进行观察:两个数 均为奇数,则花费 代价将二者均 ,使得其均为偶数。这便是答案的上界。若对两个及以上的数进行多次操作,明显不优于上述情况。
于是,对 排序。
此时只有对一个数进行操作的情况了。
在简单版中,很明显,一个数至多进行一次 操作,对一个数进行大于 次 显然不优于把两个数都进行一次 的情况。具体地,从小到大枚举,对每个数 进行 操作后分解质因数,同样若覆盖到 的地方,那么答案就为把这一个位置 的代价,也就是 。
困难版中,将一个数从 一次推广到 多次的情况:
- 对于 大于 的位置 ,对其进行操作肯定不优。
- 对于 大于 的位置 ,对其至多进行一次 操作。证: 且 是 中最小的值,若 ,则有 ,因此 。
- 对于 等于 的位置,可以进行多次操作。枚举所有 的 ,然后算使 变为 的倍数的最小代价。
做到这一步,你最终会发现:Time limit exceeded on test 23。
仔细思考,就可以发现出题人可以构造一堆 卡掉。这种情况下怎么做呢?
构造了一堆 ……那么它不就退化到了类似简单版中,所有值均为 的情况了吗?!此时加两个的代价为 ,只有对 的地方 会更优!
把上面这个判掉,此时就只用判对第一个位置加多次了!
此题完结。
代码
CPP#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+5;
int _;
int n;
struct node {
int a,id;
int b;
} s[N];
int f[N];
int prime[N];
int minp[N],cnt;
int num,p[N];
int ct;
ll ans;
bool cmp(node x,node y) {
return x.b<y.b;
}
inline int get() {
char ch=getchar();
int x=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x;
}
inline void solve() {
ans=-1ll,ct=num=0;
memset(f,0,sizeof f);
n=get();
for(int i=1;i<=n;i++) {
s[i].a=get();
if(~ans) continue;
int x=s[i].a;
if(x==1) continue;
for(int j=minp[x];x>1;j=minp[x]) {
if(x%j==0) {
if(f[j]) {ans=0;break;}
f[j]=1,p[++num]=j;
while(x%j==0) x/=j;
}
}
}
for(int i=1;i<=n;i++) s[i].b=get();
if(~ans) {puts("0");return;}
sort(s+1,s+1+n,cmp),sort(p+1,p+1+num);
ans=s[1].b+s[2].b;
bool flag=false;
for(int i=1;i<=n;i++) {
if(s[i].b>ans) break;
int x=s[i].a+1;
for(int j=minp[x];x>1;j=minp[x]) {
if(x%j==0) {
while(x%j==0) x/=j;
if(f[j]) {ans=s[i].b,flag=true;break;}
}
}
if(flag) break;
}
if(s[2].b!=s[1].b) {
for(int j=1;j<=num;j++) {
if(s[1].a%p[j]==0) continue;
ll x=p[j]-s[1].a%p[j];
ans=min(ans,x*s[1].b);
if(p[j]>s[1].a) break;
}
}
printf("%lld\n",ans);
return;
}
int main() {
_=get();
for(int i=2;i<=N-2;i++) {
if(!minp[i]) prime[++cnt]=i,minp[i]=i;
for(int j=1;j<=cnt&&prime[j]*i<=N-2;j++) {
minp[prime[j]*i]=prime[j];
if(i%prime[j]==0) break;
}
}
while(_--) solve();
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...