LightOJ1298 One Theorem, One Year (欧拉函数dp)

题意:给你almost-K-First-P-Prime, 如果一个数xk个质因子,且这k个质因子包含且仅包含前p个质数满足条件。 让你求Σφ(x)

思路:首先我们这p个因子一定要有,也就是剩下k-p个因子是什么了,剩下的因子每个都可以取前p个质数中的任意一个。想到这就有一种背包的感觉,然后在不知道状态转移方程的情况下,我们知道状态转移方程中的选还是不选怎么更新,就要用到欧拉函数更新了:

  1. φ(p)=p-1(p是质数)
  2. φ(p*a)=(p-1)*φ(a)(p是质数且p不能整除a)
  3. φ(p*a)=p*φ(a)(p是质数且p|a)

然后我就想到这。。。。开始搜索题解,对我来说太玄学了,看别人也没什么过渡,我是想不到。

dp[i][j]直接存的是答案,当一个质数没出现过,用到性质2,dp[i][j] = dp[i-1][j-1] * (prime[j] - 1) , 一个质数出现过可以用性质3,dp[i][j] += dp[i-1][j] * prime[j]

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
#define met(a, b) memset(a, b, sizeof(a))
using namespace std;
const int N = 4000;
const ll mod = 1000000007;
bool vis[N];
ll prime[N], dp[505][505];
void get_prime(){
    int pos = 0; vis[1] = 1;
    for(ll i = 2; i <= 3600; i++){
        if(!vis[i]) prime[++pos] = i;
        for(ll j = 1; j <= pos && prime[j]*i <= 3600; j++){
            vis[i*prime[j]] = 1;
            if(i%prime[j] == 0) break;
        }
    }
}

void init(){
    dp[0][0] = 1;
    for(int i = 1; i <= 500; i++){
        for(int j = 1; j <= i; j++){
            dp[i][j] += dp[i-1][j-1] * (prime[j] - 1) % mod;  //这个质数第一次被选
            if(i-1 >= j) dp[i][j] = (dp[i][j]+dp[i-1][j]*prime[j])%mod; //这个质数之前选过
        }
    }
}

int main(){
    get_prime();
    init();
    int T, cas = 0; cin >> T;
    while(T--){
        int k, p;
        cin >> k >> p;
        printf("Case %d: %lld\n", ++cas, dp[k][p]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/philo-zhou/p/11367801.html
one
今日推荐