[Swust OJ 838]--最优价值(0-1背包+数学)

 

题目链接:http://acm.swust.edu.cn/problem/838/

Time limit(ms): 1000        Memory limit(kb): 10000

 

Description

我们定义了这个一个函数: 

void Judge(int x, int &A, int &B, int &C)

{

    int i;

    for (A = 2; A<x; A++)

    if (x%A == 0)

    {

        B = x / A;

        break;

    }

    C = 0;

    for (i = 1; i <= x; i++)

    if (x%i == 0)

        C++;

}

对于每一个非素数X可以通过Judge函数得到A,B,C三个数。X的价值就定义为V=(A^B)%C

对于素数Y的价值V定义为:V=Y%10

现在给你一个大于1的正整数N,那么你将会有一个区间[2,N],现在你的问题是从中选择若干个互不相同的数,使其和不大于给定的另一个数S。同时使这些互不相等的数的价值总和最大。所以问题就是给定N和S,求出满足上诉条件的最大总价值。

 

Input

输入两个数N,S.(2<=N<=20000,2<=S<=60000)

 
Output

输出最大的总价值。


 Sample Input

 
3 3
Sample Output
 
3

解题思路:一个有意思的题,考了不少知识点,就相当于给定一个区间的数,找出它们的权值,然后转换为一个0-1背包问题,大致思路如下
     (1)对于a,b,c的值按照给出代码直接模拟求就是了(注意稍稍来点优化,一开始超时了Orz~~~)
     (2)判断一个数是否为素数,打表
     (3)求非素数的价值二分快速幂高精度取模
     (4)求最大总价值0-1背包
 
 代码如下:
 1 //背包,素数表,高精度取模

 2 #include <iostream>

 3 #include <cstring>

 4 #include <cstdio>

 5 #include <algorithm>

 6 #include <cmath>

 7 using namespace std;

 8 

 9 #define maxn 60005

10 typedef long long LL;

11 LL wi[maxn], vi[maxn], dp[maxn], n, s;

12 LL prime[maxn] = { 1, 1, 0 };

13 

14 void Prime(){

15     for (int i = 2; i <= maxn; i++){

16         if (!prime[i]){

17             for (int j = 2; i*j <= maxn; j++)

18                 prime[i*j] = 1;

19         }

20     }

21 }

22 

23 LL mulit_mod(LL a, LL b, LL c){

24     LL t = 1;

25     while (b){

26         if (b & 1) t = a*t % c;

27         b >>= 1;

28         a = a*a % c;

29     }

30     return t;

31 }

32 

33 

34 LL judge(LL x){

35     LL a, b, vi, t = (LL)sqrt((double)x);

36     if (!(x & 1)){

37         a = 2;

38         b = x / 2;

39     }

40     else{

41         for (a = 2; a <= t; a++){

42             if (x%a == 0){

43                 b = x / a;

44                 break;

45             }

46         }

47     }

48     vi = 0;

49     //优化一下,否则超时

50     //for (LL i = 1; i <= x; i++){

51     //  if (!(x%i)) vi++;

52     //}

53     for (LL i = 1; i <= t; i++){

54         if (!(x%i)){

55             LL e = x / i;

56             if (e > i) vi += 2;

57             else if (e == i)

58                 vi += 1;

59         }

60     }

61     return mulit_mod(a, b, vi);

62 }

63 

64 void init(){

65     Prime();

66     for (LL i = 2; i < maxn; i++){

67         wi[i] = i;

68         if (prime[i]) vi[i] = judge(i);

69         else vi[i] = i % 10;

70     }

71 }

72 

73 int main(){

74     init();

75     while (~scanf("%lld%lld", &n, &s)){

76         memset(dp, 0, sizeof(dp));

77         for (LL i = 2; i <= n; i++){

78             for (LL j = s; j >= wi[i]; j--)

79                 dp[j] = max(dp[j], dp[j - wi[i]] + vi[i]);

80         }

81         printf("%lld\n", dp[s]);

82     }

83     return 0;

84 }
View Code

 

 

你可能感兴趣的:(数学)