洛阳怀
题目大意
给定一个序列 \({a}\) , 支持无数次以下的操作:
钦定一个 \(k\), 并将 \(\forall a[i] \in \{a[1],a[2],a[3],...,a[k]\}\) 迭代为 \(\frac{a[i]}{gcd}\),其中 \(gcd\) = \(gcd(a[1],a[2],a[3],...,a[k])\).
然后该序列的得分被定义为 $$\sum _{i=1} ^n f(a[i]) , f(x)=\begin{cases} 0 & x=1 \\
f(\frac{s}{p})+1 & p \not\in b \\ f(\frac{s}{p})-1 & p \in b \end{cases}$$
\(s=x,p\) 为x的最小的质因数
通过若干次上述的操作,最大化最终的序列分数。并输出这个最大值。
\(b\) 将会提前给出
思路
考虑一种贪心,并且可以贪心地求出最终的序列 \(\{a\}\). 贪心即得到最大的可以产生正整数贡献的 \(k\) , 并对这个 \(k\) 进行上述的操作。
最后求得 \(a\) 并且计算上述值。
考虑维护一种高效率的数据结构可以快速计算 \(f(x)\) 。 钦定一个阈值 \(limit=\sqrt{\alpha}\) ,而这个 \(\forall i \in \{1,limit\} \cap Z\) 的 \(f(i)\) 可以经过预处理,而若这个 \(x>limit\) 那么经过最大值 \(log_2 \alpha\) 的处理可以计算得出。
而经过神奇的计算就能计算得出 \(\{a\}\) 了。
#include <bits/stdc++.h>
#define ex std::__gcd
#define RE register int
const int N=2005,root=32005,limit=31623;
int a[N],b[N],f[root],gcd[N];
int n,m;
std::map<int,bool> t;
void rebuild(void);
void init(void){
f[1]=0;
for(RE i=2;i<limit;++i){
bool flag=false;
for(RE j=2;j<=std::min(i,root);++j)
if(i%j){continue;}
else{int s=i,p=j;f[s]=f[s/p]+(t[p]?-1:1);flag=true;break;}
if(flag)continue;
f[i]=(t[i]?-1:1);
}
return;
}
void input(void){
scanf("%d%d",&n,&m);
for(RE i=1;i<=n;++i)
scanf("%d",a+i);
for(RE i=1;i<=m;++i)
scanf("%d",b+i),t[b[i]]=true;
return;
}
void rebuild(void){
gcd[1]=a[1];
for(RE i=2;i<=n;++i)
gcd[i]=ex(a[i],gcd[i-1]);
return;
}
#define gf get_function
int gf(int x){
if(x<limit) return f[x];
else{
for(RE j=2;j<=sqrt(x);++j)
if(!(x%j)){return gf(x/j)+(!t[j]?1:-1);}
return (!t[x]?1:-1);
}
}
int calc(int x){
int res=0;
for(RE i=1;i<=x;++i)
res+=gf(a[i]/gcd[x]),
res-=gf(a[i]);
return res;
}
void debug(int array[],int R){
for(RE i=1;i<=R;++i){
std::cout<<i<<')'<<array[i]<<':'<<gf(array[i])<<std::endl;
}
std::cout<<std::endl;
}
void open(std::string s){
std::freopen((s+".in").c_str(),"r",stdin);
std::freopen((s+".out").c_str(),"w",stdout);
}
signed main(){
open("cup");
input(),init();
for(RE i=n;i>=1;--i){
rebuild();
if(gf(gcd[i])<0)
for(RE j=1;j<=i;++j)
a[j]/=gcd[i];
}
#define rebuild rebuild()
#define initans int ans=0
#define RE register int
initans;
for(RE i=1;i<=n;++i)
ans+=gf(a[i]);
std::cout<<ans<<std::endl;
}
虽然码风很诡异,但是还是可以接受的

浙公网安备 33010602011771号