【USACO 2022FEB P】Sleeping in Class

【USACO 2022FEB P】Sleeping in Class

by AmanoKumiko

Description

最近终于线下授课了,奶牛 Bessie 十分兴奋!不幸的是,Farmer John 是一个非常无聊的讲师,因此她经常课堂上睡觉。

Farmer John 注意到了 Bessie 上课走神。他要求班上的另一个学生 Elsie 跟踪记录给定课上 Bessie 睡觉的次数。一共有 \(N\) 堂课,Elsie 记录下了 Bessie 在第 \(i\) 堂课睡了 \(a_i\) 次。所有课上 Bessie 一共睡觉的次数最多为 \(10^{18}\)

Elsie 认为自己是 Bessie 的竞争对手,所以她想让 FJ 觉得在每堂课上 Bessie 都一直睡了同样多次——让 FJ 觉得这个问题显然完全是 Bessie 的错,而不是 FJ 有时上课很无聊的问题。

Elsie 修改记录只有以下两种方式:把两堂课的记录合起来,或者把一堂课的记录分成两堂课。例如,如果 \(a=[1,2,3,4,5]\),那么如果 Elsie 将第二堂和第三堂课的记录合起来,记录就会变为 \([1,5,4,5]\)。如果 Elsie 继续选择让第三堂课的记录分为两堂,记录就可能变为 \([1,5,0,4,5],[1,5,1,3,5],[1,5,2,2,5],[1,5,3,1,5]\)\([1,5,4,0,5]\)

给定 \(Q\) 个候选的 Bessie 最不喜欢的数字 \(q_1,\ldots,q_Q\),对于每个数字,请帮助 Elsie 计算她至少要操作多少次,才能让记录里的所有数字都变成这个数字。

Input

第一行一个整数 \(N\)

第二行 \(N\) 个整数 \(a_1,a_2,\ldots, a_N\)

第三行一个整数 \(Q\)

接下来 \(Q\) 行,每行一个整数 \(q_i\),表示 Bessie 最不喜欢的数字。

Output

对于每个 \(q_i\),计算 Elsie 把记录里的每个数都变成 \(q_i\) 所需要的最小操作次数。如果不能把所有数都变成 \(q_i\),输出 \(-1\)

Sample Input

6
1 2 3 1 1 4
7
1
2
3
4
5
6
12

Sample Output

6
6
4
5
-1
4
5

Data Constraint

\(2\le N\le 10^5,1\le a_i\le 10^{18},1\le Q\le 10^5,1\le q_i\le 10^{18}\)

Solution

非常套路。。。

如果一个数大于\(q_i\),就分裂,否则加和。容易发现这样最优

然后对\(a\)做前缀和,记总和为\(S\),前缀和序列为\(s\)

于是答案就是\(\frac{S}{q}+n-2\sum_{i=1}^n[d|s_i]\)

容易发现有\(d|S,d|s_i\),于是\(d|gcd(S,s_i)\)

可以把每个前缀和先变为\(gcd(S,s_i)\)

接下来就是将\(S\)分解质因数,然后做高维后缀和

时间复杂度\(O(\omega(S)d(S))\)

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define random(x) rand()%(x)
#define LL long long
#define N 2000010

int p[8]={2,3,5,7,11,13,17,19};

LL ksc(LL x,LL y,LL z){return (x*y-(LL)((long double)x/z*y)*z+z)%z;}

LL mi(LL x,LL y,LL z){
	if(y==1)return x;
	return y&1?ksc(x,mi(ksc(x,x,z),y/2,z),z):mi(ksc(x,x,z),y/2,z);
}

bool Miller_Rabin(LL x){
	if(x<20){
		F(i,0,7)if(x==p[i])return 1;
		return 0;
	}
	if(!(x&1))return 0;
	LL u=x-1,t=0;
	while(!(u&1))u>>=1,t++;
	F(i,0,7){
		LL v=mi(p[i],u,x);
		if(v==1||v==x-1)continue;
		F(j,1,t-1){
			v=ksc(v,v,x);
			if(v==x-1)break;
		}
		if(v!=x-1)return 0;
	}
	return 1;
}

LL gcd(LL x,LL y){return !y?x:gcd(y,x%y);}

LL fx(LL x,LL y,LL z){return (ksc(x,x,z)+y)%z;}

LL Pollard_Rho(LL x){
	LL c=random(x-1)+1;
	LL s=c,t=fx(c,c,x);
	while(s!=t){
		LL d=gcd(abs(s-t),x);
		if(d>1)return d;
		s=fx(s,c,x);t=fx(fx(t,c,x),c,x);
	}
	return x;
}

vector<LL>s;

LL pr[N];
int c[N],tot;

void Fac(LL x){
	if(x==1)return;
	if(Miller_Rabin(x)){
		F(i,1,tot)if(pr[i]==x){c[i]++;return;}
		pr[++tot]=x;c[tot]=1;
		return;
	}
	if(!(x&1)){
		Fac(2);Fac(x>>1);
		return;
	}
	LL d=x;
	while(d>=x)d=Pollard_Rho(x);
	Fac(d);Fac(x/d);
}

map<LL,LL>num;

LL a[N],sum[N],ans[N];
int n,q;

void dfs(int x,LL y){
	if(x>tot){s.push_back(y);return;}
	LL tmp=1;
	F(i,0,c[x])dfs(x+1,y*tmp),tmp*=pr[x];
}

int main(){
	srand(time(0));
	scanf("%d",&n);
	F(i,1,n)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
	Fac(sum[n]);
	dfs(1,1);
	sort(s.begin(),s.end());
	F(i,0,s.size()-1)num[s[i]]=i;
	F(i,1,n)sum[i]=gcd(sum[i],sum[n]),ans[num[sum[i]]]++;
	F(i,1,tot) Fd(j,s.size()-1,0)if(!(s[j]%pr[i]))ans[num[s[j]/pr[i]]]+=ans[j];
	scanf("%d",&q);
	while(q--){
		LL x;
		scanf("%lld",&x);
		if(sum[n]%x)printf("-1\n");
		else printf("%lld\n",-2*ans[num[x]]+n+sum[n]/x);
	}
	return 0;
}
posted @ 2022-06-15 21:31  冰雾  阅读(374)  评论(0编辑  收藏  举报