codeforces 402D D. Upgrading Array(dp+数论)

题目链接:

codeforces 402D


题目大意:

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

∑i≤nf(a[i])

的最大值


题目分析:

  • 首先根据那个递推式我们知道结果就是每个数的f(x)就是它的质因数当中的好素数的个数减去坏素数的个数。
  • 然后我们知道如果某个gcd中好素数的个数小于坏素数的个数,那么我们把它除掉一定可以得到更好的结果,那么如果从最后一个数开始的话,后面的数除gcd不会影响前面的数,因为如果这部分质因数中坏素数的数量多于好素数,前面的数也一定要除掉的。
  • 所以我们贪心的倒序的做就好了。

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
#define MAX 5007
#define M 100007

using namespace std;

int n,m,a[MAX],b[MAX];
int prime[M],g[MAX];
map<int,bool> mp;

void init ( )
{
    memset ( prime , 0 , sizeof ( prime ) );
    prime[1] = prime[0] = 1;
    for ( int i = 2 ; i*i < M ; i++ )
    {
        if ( prime[i] ) continue;
        for ( int j = i*i ; j < M ; j+= i )
            prime[j] = 1;
    }
}

int gcd ( int a , int b )
{
    return b?gcd(b,a%b):a;
}

int main ( )
{
    init ();
    while ( ~scanf ( "%d%d" , &n , &m ) )
    {
        mp.clear();
        for ( int i = 0 ; i < n ; i++ )
            scanf ( "%d" , &a[i] );
        for ( int i = 0 ; i < m ; i++ )
            scanf ( "%d" , &b[i] );
        g[0] = a[0];
        for ( int i = 0 ; i < m ; i++ )
            mp[b[i]] = true;
        for ( int i = n-1 ; i >= 0 ; i-- )
        {
            int x = 0;
            for ( int j = 0 ; j <= i ;j++ )
                x = gcd ( x , a[j] );
            int xx = x;
            int num1,num2;
            num1 = num2 = 0;
            for ( int j = 2 ; j*j <= x ; j++ )
            {
                if ( prime[j] ) continue;
                if ( x%j ) continue;
                bool flag = mp[j];
                while ( x%j == 0 )
                {
                    x/= j;
                    if ( flag ) num1++;
                    else num2++;
                }
            }
            if ( x > 1 )
            {
                if ( mp[x] ) num1++;
                else num2++;
            }
            if ( num1 > num2 )
                for ( int j = 0 ; j <= i ; j++ )
                    a[j] /= xx;
        }
        int ans = 0;
        for ( int i = 0 ; i < n ; i++ )
        {
            int x = a[i];
            for ( int j = 2 ; j*j <= x ; j++ )
            {
                if ( prime[j] ) continue;
                if ( x%j ) continue;
                bool flag = mp[j];
                while ( x%j == 0 )
                {
                    x /= j;
                    if ( flag ) ans--;
                    else ans++;
                }
            }
            if ( x > 1 )
            {
                if ( mp[x] ) ans--;
                else ans++;
            }
        }
        printf ( "%d\n" , ans );
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-20 22:13:26

codeforces 402D D. Upgrading Array(dp+数论)的相关文章

Codeforces 57C Array dp暴力找规律

题目链接:点击打开链接 先是计算非递增的方案, 若非递增的方案数为x, 则非递减的方案数也是x 答案就是 2*x - n 只需求得x即可. 可以先写个n3的dp,然后发现规律是 C(n-1, 2*n-1) 然后套个逆元即可. #include<iostream> #include<cstdio> #include<vector> #include<string.h> using namespace std; #define ll long long #def

codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新

DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-14) Description In mathematical terms, the sequence Fn of Fibonacci numbers is defi

[2016-04-09][codeforces][660][A][ Co-prime Array]

时间:2016-04-09 22:50:56 星期六 题目编号:[2016-04-09][codeforces][660][A][ Co-prime Array] 题目大意:给定一个数列,问至少需要插入多少个1 1091 109中的任一数字,才能使得相邻两个数字是互质的,输出最少次数和最后的数列 分析:直接扫一遍,相邻元素不互质的,中间插个1, #include<cstdio> #include<vector> using namespace std; const int maxn

Codeforces 442C Artem and Array(stack+贪心)

题目连接:Codeforces 442C Artem and Array 题目大意:给出一个数组,每次删除一个数,删除一个数的得分为两边数的最小值,如果左右有一边不存在则算作0分.问最大得分是多少. 解题思路:首先将连续的a,b,c,a > b && c > b的情况将c掉,获得min(a,b)分,这样处理后数组变成一个递増再递减的序列,除了最大和第二大的取不到,其他数字均可以得分. 样例:4 10 2 2 8 #include <cstdio> #include

Codeforces 396B On Sum of Fractions 数论

题目链接:Codeforces 396B On Sum of Fractions 题解来自:http://blog.csdn.net/keshuai19940722/article/details/20076297 题目大意:给出一个n,ans = ∑(2≤i≤n)1/(v(i)*u(i)), v(i)为不大于i的最大素数,u(i)为大于i的最小素数, 求ans,输出以分式形式. 解题思路:一开始看到这道题1e9,暴力是不可能了,没什么思路,后来在纸上列了几项,突然想到高中时候求等差数列时候用到

Codeforces 360C Levko and Strings dp

题目链接:点击打开链接 题意: 给定长度为n的字符串s,常数k 显然s的子串一共有 n(n-1)/2 个 要求找到一个长度为n的字符串t,使得t对应位置的k个子串字典序>s #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<set> using namespace std; #

Educational Codeforces Round 21 D. Array Division

题目链接:Educational Codeforces Round 21 D. Array Division 题意: 给你n个数,现在你可以改变1<=个数的位置,然后问你是否存在有一个k,使得sum(a[i])(1<=i<=k)==sum(a[j])(k+1<=j<=n) 题解: 分析: 如果需要将一个数移动,无非就是将这个数从第一部分移到第二部分,或者从第二部分移到第一部分. 所以,我们只需要开两个map来记录一下两部分有哪些数. 当两部分的差值/2等于其中一部分的一个数时

CodeForces 30C Shooting Gallery 简单dp

题目链接:点击打开链接 给定n个气球 下面n行 x y t val 表示气球出现的坐标(x,y) 出现的时刻t,气球的价值val 枪每秒移动1个单位的距离 问: 射击的最大价值,开始时枪瞄准的位置任意. 思路: dp一下.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set

Codeforces 459E Pashmak and Graph(dp+贪心)

题目链接:Codeforces 459E Pashmak and Graph 题目大意:给定一张有向图,每条边有它的权值,要求选定一条路线,保证所经过的边权值严格递增,输出最长路径. 解题思路:将边按照权值排序,每次将相同权值的边同时加入,维护每个点作为终止点的最大长度即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 3