您的位置:首页 > 其它

LightOj 1298 - One Theorem, One Year(DP + 欧拉)

2016-11-04 17:14 1736 查看
题目链接:http://lightoj.com/volume_showproblem.php?problem=1298

题意:给你两个数 n, p,表示一个数是由前 k 个素数组成的,共有 n 个素数,然后求这样的所有的数的欧拉和;

例如 n = 3, p=2; 前两个素数是2,3, 然后因为n=3,所以要再选一个素数组成一个数,有两种选择2*3*2=12 和 2*3*3=18 结果就是[b]Φ(12)+[b]Φ(18) = 10;[/b][/b]

[b][b]我们可以用dp[i][j] 表示前 j 个素数中选择 i 个的结果,[b]Φ
= n*(p[i]-1)/p[i] * (p[i+1]-1)/p[i+1] * ... ;
[/b][/b][/b]

[b][b][b]那么对于p[j]是第一次选择的话,那么dp[i][j] += dp[i-1][j-1]*(p[j]-1),因为相当于是第i个素数是p[j],而且p[j]是第一次被选择,所以要*(p[j]-1)[/b][/b][/b]

[b][b][b]当p[j]不是第一次被选择时,dp[i][j] += dp[i-1][j]*p[j],因为p[j]已经出现过一次了[/b][/b][/b]

[b][b][b]要先打表再求,不然会TLE;[/b][/b][/b]

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <bitset>
#include <iostream>
#include <time.h>

typedef long long LL;

using namespace std;

const int N = 5050;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;

int k = 1, p[1100];
bool f
;

void Init()
{
for(int i=2; i<N; i++)
{
if(f[i])continue;
p[k++] = i;
for(int j=i+i; j<N; j+=i)
f[j] = 1;
}
///printf("%d\n", k);
}
LL dp[505][505];

void Dp()
{
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]*(p[j]-1);
if(i>j)///只有当 i > j 时才能选p[j]大于二次;
dp[i][j] += dp[i-1][j]*p[j];
dp[i][j] %= mod;
}
}
}

int main()
{
Init();

Dp();

int T, t = 1;

scanf("%d", &T);

while(T --)
{
int n, K;

scanf("%d %d", &n, &K);

printf("Case %d: %lld\n", t++, dp
[K]);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: