Codeforces Round #236 (Div. 二)_Upgrading Array
Codeforces Round #236 (Div. 2)__Upgrading Array
题目链接
- 思路:
求出所有前缀区间的gcd,然后倒着处理。对于当前位置的前缀gcd,求一下这个数的f函数值,如果是负的,那么肯定去掉是对的。然后对之前的位置,gcd值要除以它之后的区间已经除过的数(不用依次去除,只用记录一下之前除的数是多少,然后计算到一个区间的时候,直接gcd除以这个数即可),然后依次向前处理直到结束即可 - 分析:
1.为什么要倒着处理呢,因为题目要求每次都是前缀操作,那么对于最后一个区间(最长的区间),没有人会对他产生影响。
2.方法的正确性:由于是前缀区间的gcd,那么最后一个区间的gcd肯定包括在其他所有区间中,而且题目的操作单位是gcd而不是质因子。那么对于前边的区间,可以分成两个部分,一个是最后一个区间的gcd值,另一个是剩下的部分。
考虑两种情况:(1)最后区间的gcd为正:不妨设在i位置时候需要除去,那么在最后一个区间不除肯定比较优,因为少除去了一部分正值;(2)如果为负,那么同理会多除去一部分负值,也最优。所以这个策略是没错的
int na, nb;
int ipt[MAXN], gcd[MAXN], bp[MAXN];
void solve(int& n, int v)
{
if (binary_search(bp, bp + nb, v))
n--;
else
n++;
}
int fun(int n)
{
int ret = 0;
for (int i = 2; i * i <= n; i++) //这里使用 i <= n / i的话会超时...无奈
{
while (n % i == 0)
{
solve(ret, i);
n /= i;
}
}
if (n > 1)
solve(ret, n);
return ret;
}
int main()
{
// freopen("in.txt", "r", stdin);
while (~RII(na, nb))
{
int ans = 0, used = 1, t;
gcd[0] = 0;
FE(i, 1, na)
{
RI(ipt[i]);
gcd[i] = __gcd(gcd[i - 1], ipt[i]);
}
REP(i, nb) RI(bp[i]);
sort(bp, bp + nb);
FE(i, 1, na)
ans += fun(ipt[i]);
FED(i, na, 1)
{
if ((t = fun(gcd[i] / used)) < 0)
{
ans -= t * i;
used = gcd[i];
}
}
cout << ans << endl;
}
return 0;
}