洛阳怀

题目大意

给定一个序列 \({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;
}

虽然码风很诡异,但是还是可以接受的

posted @ 2023-09-30 21:51  q(x)  阅读(29)  评论(0)    收藏  举报