这次真的是好久没更新博客了,好几个月了都没怎么做过题了...

马上又要有一系列的比赛了,是时候找回状态了,既然选择了再战一年,就必须要全力以赴。

闲话不多说了,进入正题吧~

思路:离散化dp。

题目描述有点生涩,不过看出来了就是:给你n个数(1-n),让你从中选出一些数,使这些数的最小公倍数大于等于m,问共有多少种选择。

刚开始有想到DP,但一看到m那么大就直接凌乱了。

虽然m很大,但是会用到的状态最多才3w+ ,想到这一点这题就可解了。

因为这些有用的状态不是连续的,m还那么大,所以要用到离散化,所以用map最为方便。

之前没用过stl,只知道很强大,今天学了一个map,算是感觉到了。

View Code
 1 # include<stdio.h> 
2 # include<string.h>
3 # include<map>
4 using namespace std;
5 map<__int64 ,__int64 > dp[45];
6 int gcd(__int64 a,__int64 b)
7 {
8 __int64 temp;
9 while(a%b!=0)
10 {
11 temp=a%b;
12 a=b;
13 b=temp;
14 }
15 return b;
16 }
17 __int64 lcm(__int64 a,__int64 b)
18 {
19 return a*b/gcd(a,b);
20 }
21 void solve()
22 {
23 int i;
24 dp[1][1]=1;
25 for(i=2;i<=40;i++)
26 {
27 dp[i]=dp[i-1];
28 dp[i][i]++;
29 map<__int64 ,__int64 > ::iterator iter;
30 for(iter=dp[i-1].begin();iter!=dp[i-1].end();iter++)
31 {
32 __int64 lc=lcm(iter->first,i);
33 dp[i][lc]+=iter->second;
34 //dp[i][lc]+=dp[i-1][iter->first];
35 }
36 }
37 /*int Max=0;
38 for(i=2;i<=40;i++)
39 if(dp[i].size()>Max) Max=dp[i].size();
40 printf("%d\n",Max);
41
42 //Max最大为3w+
43
44 */
45 }
46 int main()
47 {
48 int t,ncase,n;
49 __int64 sum,m;
50 solve();
51 scanf("%d",&ncase);
52 for(t=1;t<=ncase;t++)
53 {
54 scanf("%d%I64d",&n,&m);
55 sum=0;
56 map<__int64 ,__int64 > ::iterator it;
57 for(it=dp[n].begin();it!=dp[n].end();it++)
58 {
59 if(it->first>=m) sum+=it->second;
60 }
61 printf("Case #%d: %I64d\n",t,sum);
62 }
63 return 0;
64 }

 

posted on 2012-04-07 18:14  奋斗青春  阅读(335)  评论(0编辑  收藏  举报