Codeforces Round #538 (Div. 2) C D

3 篇文章 0 订阅
2 篇文章 0 订阅

默默自闭补题 = =

Codeforces Round #538 (Div. 2)


C题

题意
给n和b,求十进制数 n! 转化成b之后有多少个0 ( 1 <= n <= 10^18 , 2 <= b <= 10^12 )

思路
有多少个零,实际上是求(n!)%(b^k)==0时,k的最大值。(可以试一下十进制转二进制)

因为n和b比较大,不能直接求,所以需要把 b 化成 p1^b1 * p2 ^ b2 * p3 ^ b3 … 的形式,px是质因数,bx是该质因数的幂。在看看 n! 中对于b的每个px有多少个,个数 / bx 就可能是答案。因为要满足(n!)%(b^k)==0,取这些可能的答案中的最小的,就是最终的答案。

对于 “ n! 中对于b的每个px有多少个 ” 怎么求,设答案为cnt
cnt = n/p + n/(p * p) + n/(p * p * p) + … 向下取整
当然实际这么写会爆 long long,具体看代码

代码

#include  <algorithm>//           ¨|¨|¨|        ¨|¨|¨|¨|
#include   <iostream>//         ¨}¨}¨}¨}      ¨~¨~¨~
#include    <cstring>//        ¨~¨~ ¨~¨~    ¨~¨~
#include    <stdio.h>//       ¨~¨~  ¨~¨~   ¨~¨~
#include     <vector>//      ¨~¨~   ¨~¨~  ¨~¨~
#include      <cmath>//     ¨~¨~    ¨~¨~  ¨~¨~
#include      <queue>//    ¨~¨~ ¨~¨~¨~¨~  ¨~¨~
#include        <map>//   ¨~¨~      ¨~¨~   ¨~¨~
using namespace std ;//  ¨~¨~       ¨~¨~    ¨~¨~¨~
typedef long long ll;// ¨~¨~        ¨~¨~      ¨~¨~¨~¨~¨~
#define pi pair<int,int>  ///
#define P(x,y) make_pair(x,y)
const int maxn = 1e5 + 5;
const ll mod = 998244353;
ll read()
{
	ll x=0;char ch=getchar(); bool flag = false;
	if(ch=='-') { flag = true; ch = getchar();}
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	if(flag) return -x;  else return x;
}

ll prime[maxn*10],c[maxn*10],tot;
void get_prime(ll b){
    ll tmp = (ll)sqrt((double)b),i;
    for(i=2;i<=tmp;i++){
        if(b%i==0){
            prime[++tot] = i;
            while(b%i==0){
                c[tot]++;
                b /= i;
            }
        }
    }
    if(b>1){
        prime[++tot] = b;
        c[tot]++;
    }
}
ll mx(ll n,ll p){
    ll t = 0;
    while(n){
        t += n/p;
        n /= p;
    }
    return t;
}

int main()
{   if(fopen("in.txt","r")) freopen("in.txt","r",stdin);
    ll n,b,ans = 0x3f3f3f3f3f3f3f3f;
    n = read(); b = read();
    get_prime(b);
    for(ll i=1;i<=tot;i++){
        ans = min(ans,mx(n,prime[i])/c[i]);
    }
    printf("%I64d\n",ans);
    return 0;
}

D题

题意
给一个数字n,下面给出n个数字ci
1 <= n <= 5000 ,1 <= ci <= 5000
要求每一次操作,选择某个连续的、数字相同的区域,把这些数字全部改成某种数字,求最少多少次操作,使得n个数字全部变成相同的。

思路
区间dp = = 没想出来
dp [ i ] [ j ] 表示区间 [ i , j ] 数字全部相同时,最少要多少步,初始为0步
首先要把连续相同的数字变成一个数字: 1 1 1 2 2 3 3 1 1 -> 1 2 3 1
因为相邻相同,对答案没有贡献,还会影响判断
然后对于长度为len的新数列,从区间长度为2,3,4 … len的区间开始dp
如果 a[ i ] = a[ j ] ,则dp [ i ] [ j ] = dp [ i + 1 ] [ j - 1 ] + 1
(dp [ i ] [ j ] 为里面的区间:[ i + 1 , j - 1 ] 的dp答案再 + 1)
否则 dp [ i ] [ j ] = min ( dp [ i+1 ][ j ] + 1 ,dp [ i ] [ j - 1 ] + 1 )
(该dp[ i ] [ j ] 要不数字变为右边区间 [ i+1 , j ] 的数字,要不数字变为左边区间 [ i , j - 1 ]的数字,两者操作数取最小)

代码

#include  <algorithm>//           ¨|¨|¨|        ¨|¨|¨|¨|
#include   <iostream>//         ¨}¨}¨}¨}      ¨~¨~¨~
#include    <cstring>//        ¨~¨~ ¨~¨~    ¨~¨~
#include    <stdio.h>//       ¨~¨~  ¨~¨~   ¨~¨~
#include     <vector>//      ¨~¨~   ¨~¨~  ¨~¨~
#include      <cmath>//     ¨~¨~    ¨~¨~  ¨~¨~
#include      <queue>//    ¨~¨~ ¨~¨~¨~¨~  ¨~¨~
#include        <map>//   ¨~¨~      ¨~¨~   ¨~¨~
using namespace std ;//  ¨~¨~       ¨~¨~    ¨~¨~¨~
typedef long long ll;// ¨~¨~        ¨~¨~      ¨~¨~¨~¨~¨~
#define pi pair<int,int>  ///
#define P(x,y) make_pair(x,y)
const int maxn = 1e5 + 5;
const ll mod = 998244353;
ll read()
{
	ll x=0;char ch=getchar(); bool flag = false;
	if(ch=='-') { flag = true; ch = getchar();}
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	if(flag) return -x;  else return x;
}

int dp[5005][5005],a[5005];

int main()
{   if(fopen("in.txt","r")) freopen("in.txt","r",stdin);
    int T,n,m,k,i,sum,j,t,tmp;
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    k = unique(a+1,a+1+n) - (a+1);
    for(i=1;i<=k;i++) cout<<a[i]<<" ";
    cout<<endl;
    for(t=1;t<k;t++){
        for(i=1,j=t+i;(j=t+i)<=k;i++){
            if(a[i]==a[j]) dp[i][j] = dp[i+1][j-1] + 1;
            else dp[i][j] = min(dp[i+1][j]+1,dp[i][j-1]+1);
        }
    }
    printf("%d\n",dp[1][k]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值