[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

 

 
posted @ 2015-06-28 00:52  繁夜  阅读(442)  评论(0编辑  收藏  举报