[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 |
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 }
如果这是你所爱的,就不要让自己后悔~~~