Denso Create Programming Contest 2022 Winter(AtCoder Beginner Contest 280)D-F

前三个题目太简单了 我就不写了 

D 我的想法是分解质因数 将它分解成a1^p1 * a2 ^ p2 * a3 ^ p3的形式 

那么很明显 我们假设Ni表示最小的满足能被ai^pi整除的整数 那么答案就是N = max(N1,N2....Nn)

考虑怎么计算Ni 

我们将N的阶乘理解成每次加入一个末尾的数相乘 那么当每次加入的数是ai的倍数的时候 才距离我们想要的答案更进一步 

所以可以直接枚举Ni为多少倍的ai 然后算能不能满足即可 

#include<bits/stdc++.h>
using namespace std ;
#define maxn 400100
#define int long long
int read(){
    int ans = 0 , f = 1 ; char ch = getchar() ;
    while ( !isdigit(ch) ){ if( ch == '-' ) f = -1 ; ch = getchar() ; }
    while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ;
    return ans * f ;
}
int a[110] , cnt[110], tot; 
int ans ; 
int calc1(int x , int y){
    int sum = 0 ; 
    while(x % y == 0){
        sum++ ; 
        x /= y ; 
    }
    return sum ; 
}
int calc(int d , int p){
    int sum = 0 ;
    for(int i = 1 ; ; i++){
        sum += calc1(i * d , d) ; 
        if(sum >= p){
            return i * d ; 
        }
    } 
}
signed main(){
//    freopen("test.in" , "r" , stdin) ;
//    freopen("test.out" , "w" , stdout) ;
    int k = read() ; int mx = sqrt(k) ; 
    for(int i = 2 ; i <= mx ; i++){
        if(k % i == 0){
            a[++tot] = i ; 
            while(k % i == 0)
                cnt[tot]++ , k /= i ; 
        }
    }
    if(k != 1) a[++tot] = k , cnt[tot] = 1 ; 
    for(int i = 1 ; i <= tot ; i++){
        ans = max(ans , calc(a[i] , cnt[i])) ; 
    }
    printf("%lld" , ans) ; 
    return 0 ;
}

E题 经典期望题 我以前写过一个这种期望的博客 https://www.luogu.com.cn/blog/zht20040830/shi-yue-yue-sai-t2-post

其实就是直接设状态去递推就完事了 令dp[i] 为消灭i值的怪兽的期望操作数 那么每一次要么从i-1转移 要么从i-2转移 

看代码就可以了

#include<bits/stdc++.h>
using namespace std ;
#define maxn 400100
#define int long long
int read(){
    int ans = 0 , f = 1 ; char ch = getchar() ;
    while ( !isdigit(ch) ){ if( ch == '-' ) f = -1 ; ch = getchar() ; }
    while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ;
    return ans * f ;
}
const int mod = 998244353 ; 
int pac ; 
int p , n ; 
int f[maxn] ; 
int p1 , p2 ; 
int ksm(int a , int b){
    int sum = 1 ; 
    while(b){
        if(b & 1) sum = sum * a % mod ; 
        a = a * a % mod ;
        b >>= 1 ; 
    }
    return sum ; 
}
int findf(int x){
    if(f[x]) return f[x] ; 
    return f[x] = (findf(x - 1) * p1 % mod + findf(x - 2) * p2 % mod + 100) * pac % mod  ;  
}
signed main(){
//    freopen("test.in" , "r" , stdin) ;
//    freopen("test.out" , "w" , stdout) ;
    n = read() , p = read() ; 
    p2 = p ; p1 = 100 - p ; 
    pac = ksm(100 , mod - 2 ) ; 
    f[1] = 1 ; f[2] = p2 * pac % mod + 2 * p1 * pac % mod ; 
    printf("%lld" , findf(n)) ; 
    return 0 ;
}

F题 理解题意很重要 到达目的地后是可以不用停下来的!!!!!

不一定要停下来!!!

分情况讨论 

1。不能到达 那就是不在一个图里面 所以用并查集即可

2.可以到达 但是inf 

很明显 如果出现了一个连通分量并且以一个点为起点 到达某一个点有两种不同的dis值 那么这种情况下肯定是inf 因为我可以一直在这个环上沿着正方向转圈圈 

所以如果x和y所在图上有这样一种连通分量的存在 肯定是inf了 最后把这种集合标记一下即可

那么距离要怎么求呢

我们以这个集合的f[i] (并查集里面的概念)为起点去dfs 算dis 最后dis[y] - dis[x] 就是答案了 

(还没写 因为没空 先留坑 其实是tarjan不太熟练了

posted @ 2022-12-05 15:13  Vellichor_zht  阅读(59)  评论(0)    收藏  举报