默默自闭补题 = =
Codeforces Round #538 (Div. 2)
题意
给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 // ¨|¨|¨| ¨|¨|¨|¨|
#include // ¨}¨}¨}¨} ¨~¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
using namespace std ;// ¨~¨~ ¨~¨~ ¨~¨~¨~
typedef long long ll;// ¨~¨~ ¨~¨~ ¨~¨~¨~¨~¨~
#define pi pair ///////////////////////////////
#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;
}
题意
给一个数字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 // ¨|¨|¨| ¨|¨|¨|¨|
#include // ¨}¨}¨}¨} ¨~¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~¨~¨~ ¨~¨~
#include // ¨~¨~ ¨~¨~ ¨~¨~
using namespace std ;// ¨~¨~ ¨~¨~ ¨~¨~¨~
typedef long long ll;// ¨~¨~ ¨~¨~ ¨~¨~¨~¨~¨~
#define pi pair ///////////////////////////////
#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;
}