码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 402D Upgrading Array:贪心 + 数学

时间:2018-01-06 23:21:08      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:影响   pre   bad   i++   air   set   com   前缀   ++   

题目链接:http://codeforces.com/problemset/problem/402/D

题意:

  给你一个长度为n的数列a[i],又给出了m个“坏质数”b[i]。

  定义函数f(s),其中p是s的最小质因子:

    f(1) = 0

    f(s) = f(s/p) + 1 (p不是坏质数)

    f(s) = f(s/p) - 1 (p是坏质数)

  你可以任意次数地进行操作:给a[1 to i]的每个数都除以gcd(a[1 to i])。

  问你 ∑ f(a[i)最大为多少。

 

题解:

  函数f(s)的实际意义是:

    s的质因子中,好质数的个数 - 坏质数的个数。

  每一次操作的实际意义是:

    对于所选前缀中的每个数,从它的质因子中丢掉若干个好质数和坏质数。

  显然,要想使 ∑ f(a[i)更大,则:

    对于每次操作,当且仅当丢掉的坏质数的个数大于丢掉好质数的个数时,才会执行操作。

 

  然后考虑操作顺序所带来的影响:

    假设有i < j。

    如果先执行操作opt(1 to i),再执行操作opt(1 to j):

      由于第一次操作已经使得gcd(a[1 to i])变为1,并且区间[1,j]包含着[1,i]。

      所以此时gcd(a[1 to j]) = 1,即第二次操作是无效的。

      也就是说,a[i+1 to j]中的一些数,本身可以对答案做出贡献,却因为第一次操作而失效。

    如果先执行操作opt(1 to j),再执行操作opt(1 to i):

      因为第一次操作已经将a[i+1 to j]中可以除掉的坏质数全部除掉,并将a[1 to i]中的一部分坏质数除掉。

      所以在第二次操作时,只要将a[1 to i]中剩下的坏质数除掉即可,不会有任何浪费。

  所以从后往前贪心地操作就好啦。

 

  复杂度分析:

    (1)预处理出前缀gcd[i]:

      O(n*logn)

    (2)处理出所有操作完成后的数列a[i](要分解质因数):

      O(n*sqrt(n))

    (3)算出所有的f(a[i])(还要分解质因数):

      O(n*sqrt(n))

 

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <math.h>
  5 #include <set>
  6 #define MAX_N 5005
  7 
  8 using namespace std;
  9 
 10 int n,m;
 11 int a[MAX_N];
 12 int g[MAX_N];
 13 set<int> st;
 14 
 15 void read()
 16 {
 17     cin>>n>>m;
 18     for(int i=1;i<=n;i++)
 19     {
 20         cin>>a[i];
 21     }
 22     int x;
 23     for(int i=1;i<=m;i++)
 24     {
 25         cin>>x;
 26         st.insert(x);
 27     }
 28 }
 29 
 30 int gcd(int a,int b)
 31 {
 32     return b==0 ? a : gcd(b,a%b);
 33 }
 34 
 35 void cal_g()
 36 {
 37     g[1]=a[1];
 38     for(int i=2;i<=n;i++)
 39     {
 40         g[i]=gcd(g[i-1],a[i]);
 41     }
 42 }
 43 
 44 pair<int,int> cal_p(int x)
 45 {
 46     int good=0;
 47     int bad=0;
 48     for(int i=2,t=sqrt(x);i<=t;i++)
 49     {
 50         int cnt=0;
 51         while(x%i==0)
 52         {
 53             x/=i;
 54             cnt++;
 55         }
 56         if(cnt)
 57         {
 58             if(st.count(i)>0) bad+=cnt;
 59             else good+=cnt;
 60         }
 61     }
 62     if(x!=1)
 63     {
 64         if(st.count(x)>0) bad++;
 65         else good++;
 66     }
 67     return pair<int,int>(good,bad);
 68 }
 69 
 70 bool check(int x)
 71 {
 72     pair<int,int> p=cal_p(x);
 73     return p.first<p.second;
 74 }
 75 
 76 void cal_a()
 77 {
 78     int d=1;
 79     for(int i=n;i>=1;i--)
 80     {
 81         if(check(g[i]/d)) d=g[i];
 82         a[i]/=d;
 83     }
 84 }
 85 
 86 int cal_f()
 87 {
 88     int ans=0;
 89     for(int i=1;i<=n;i++)
 90     {
 91         pair<int,int> p=cal_p(a[i]);
 92         ans+=p.first-p.second;
 93     }
 94     return ans;
 95 }
 96 
 97 void work()
 98 {
 99     cal_g();
100     cal_a();
101     cout<<cal_f()<<endl;
102 }
103 
104 int main()
105 {
106     read();
107     work();
108 }

 

Codeforces 402D Upgrading Array:贪心 + 数学

标签:影响   pre   bad   i++   air   set   com   前缀   ++   

原文地址:https://www.cnblogs.com/Leohh/p/8215403.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!