题目链接: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:

 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <set>
#define MAX_N 5005 using namespace std; int n,m;
int a[MAX_N];
int g[MAX_N];
set<int> st; void read()
{
cin>>n>>m;
for(int i=;i<=n;i++)
{
cin>>a[i];
}
int x;
for(int i=;i<=m;i++)
{
cin>>x;
st.insert(x);
}
} int gcd(int a,int b)
{
return b== ? a : gcd(b,a%b);
} void cal_g()
{
g[]=a[];
for(int i=;i<=n;i++)
{
g[i]=gcd(g[i-],a[i]);
}
} pair<int,int> cal_p(int x)
{
int good=;
int bad=;
for(int i=,t=sqrt(x);i<=t;i++)
{
int cnt=;
while(x%i==)
{
x/=i;
cnt++;
}
if(cnt)
{
if(st.count(i)>) bad+=cnt;
else good+=cnt;
}
}
if(x!=)
{
if(st.count(x)>) bad++;
else good++;
}
return pair<int,int>(good,bad);
} bool check(int x)
{
pair<int,int> p=cal_p(x);
return p.first<p.second;
} void cal_a()
{
int d=;
for(int i=n;i>=;i--)
{
if(check(g[i]/d)) d=g[i];
a[i]/=d;
}
} int cal_f()
{
int ans=;
for(int i=;i<=n;i++)
{
pair<int,int> p=cal_p(a[i]);
ans+=p.first-p.second;
}
return ans;
} void work()
{
cal_g();
cal_a();
cout<<cal_f()<<endl;
} int main()
{
read();
work();
}

Codeforces 402D Upgrading Array:贪心 + 数学的更多相关文章

  1. CodeForces 402D Upgrading Array (数学+DP)

    题意:给出一个数列,可以进行一种操作将某一个前缀除去他们的gcd,有一个函数f(x),f(1) = 0 , f(x) = f(x/p)+1,f(x) = f(x/p)-1(p是坏素数), 求 sum( ...

  2. CodeForces ---596B--Wilbur and Array(贪心模拟)

    Wilbur and Array Time Limit: 2000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Su ...

  3. Codeforces 494D Upgrading Array

    http://codeforces.com/contest/494/problem/D 题意:给一个数组,和一个坏质数集合,可以无数次地让1到i这些所有数字除以他们的gcd,然后要求Σf(a[i])的 ...

  4. Codeforces 1054D Changing Array 贪心+异或和

    题意 给一个长度为\(n\)的位数为\(k\)的整数数列\(a\),一次操作可将任意\(a_i\)取反,问经过任意次操作后最多有多少个区间异或和不为\(0\) 分析 求出前缀异或和,区间异或和为\(0 ...

  5. 贪心/数学 Codeforces Round #212 (Div. 2) A. Two Semiknights Meet

    题目传送门 /* 贪心/数学:还以为是BFS,其实x1 + 4 * k = x2, y1 + 4 * l = y2 */ #include <cstdio> #include <al ...

  6. codeforces 704B - Ant Man 贪心

    codeforces 704B - Ant Man 贪心 题意:n个点,每个点有5个值,每次从一个点跳到另一个点,向左跳:abs(b.x-a.x)+a.ll+b.rr 向右跳:abs(b.x-a.x) ...

  7. Codeforces 482B Interesting Array(线段树)

    题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...

  8. Codeforces 1077C Good Array 坑 C

    Codeforces 1077C Good Array https://vjudge.net/problem/CodeForces-1077C 题目: Let's call an array good ...

  9. codeforces 482B. Interesting Array【线段树区间更新】

    题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val. 就是区间l---r上的与的值为val,最后问你原来的数 ...

随机推荐

  1. C#中YieldReturn的用法

    Yield Return 和 Yield Break 的出现是为了简化迭代器. 类如果能被遍历则必须有IEnumerator<string> GetEnumerator() 方法, 并有用 ...

  2. python实现测试中常用的脚本(待完善)

    一. Python操作MySQL数据库,简单的增删改查 # coding=utf-8 ''' Created on 2015年5月12日 @author: Administrator ''' impo ...

  3. vi 详解

    1.vi的基本概念 基本上vi可以分为三种状态,分别是命令模式(command mode).插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下: ...

  4. 【Python+selenium Wendriver API】之操作警告和弹出框

    参考文章: <Python+Selenium笔记(九):操作警告和弹出框>

  5. OpenResty — Nginx全能插件版

    官网: http://openresty.org/ 虽然是中国人做的,但没几个汉字..... 我用Nginx,是这样一个过程: 1. 系统rpm中的nginx,能让其跑起来 2. 玩配置文件 3. 玩 ...

  6. eclipse 导入maven 父子项目

    你先要确认svn上是否是maven项目,否则要自己重新建一个maven项目然后直接引入目录了.如果确认是maven项目,那么有个两个方案.案一:先用任何client软件将svn下载.然后在eclips ...

  7. Keil 中 Program Size: Code RO-data RW-data ZI-data 所代表的意思

    在Keil中编译工程成功后,在下面的Bulid Ouput窗口中会输出下面这样一段信息: Program Size: Code=6320 RO-data=4864 RW-data=44 ZI-data ...

  8. vue+mousemove实现拖动,鼠标移动过快拖动就失效

    今天用vue+原生js的mousemove事件,写了个拖动,发现只能慢慢拖动才行,鼠标只要移动快了,就失效,不能拖动了: 搞了半天在,总算解决了,但是问题的深层原理还没搞清楚,知道的大侠可以留言分享, ...

  9. 使用CSDN CODE来存放OPENSTACK位于GITHUB上的源代码

    use CSDN CODE to pull openstack codes 2014-11-20 Author:Hyphen 问题 直接从GITHUB上获代替码,常常是没保障,特别是用DEVSTACK ...

  10. iOS启动页加载广告

    1.定义全局成员变量 @interface AppDelegate () @property (strong, nonatomic) UIImageView *adImageView; @proper ...