CF2154C
你说得对。但是无论什么代价都在所不惜。(题目名字)
题面
有一个长度为
对于这一题的简单版:
对于这一题的困难版:
题解
妙妙贪心思维题,从简单版开始想。
首先,特判本来已有一对不互质的数的情况。具体地,对于每个
接着,对数列的性质进行观察:两个数
于是,对
此时只有对一个数进行操作的情况了。
在简单版中,很明显,一个数至多进行一次
困难版中,将一个数从
- 对于
b_{i} 大于b_{1}+b_{2} 的位置i ,对其进行操作肯定不优。 - 对于
b_{i} 大于b_{1} 的位置i ,对其至多进行一次+1 操作。证:b_{2} \ge b_{1} 且b_{2} 是\ge b_{1} 中最小的值,若b_{i}>b_{1} ,则有b_{i} \ge b_{2} ,因此2 \times b_{i} \ge b_{2}+b_{1} 。 - 对于
b_{i} 等于b_{1} 的位置,可以进行多次操作。枚举所有f_{x}=1 的x ,然后算使a_{i} 变为x 的倍数的最小代价。
做到这一步,你最终会发现:Time limit exceeded on test 23。
我想了一堆法子优化都被卡死了,这是算法出了问题!
仔细思考,就可以发现出题人可以构造一堆
构造了一堆
把上面这个判掉,此时就只用判对第一个位置加多次了!
此题完结。
代码
#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;
}