Codeforces Round #236 (Div. 2)__Upgrading Array

来源:互联网 发布:php超链接输出成文本 编辑:程序博客网 时间:2024/05/01 02:08

题目链接

  • 思路:
    求出所有前缀区间的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;}


8 0
原创粉丝点击