BZOJ1978: [BeiJing2010]取数游戏 game

1978: [BeiJing2010]取数游戏 game

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 650  Solved: 400
[Submit][Status]

Description

小 C 刚学了辗转相除法,正不亦乐乎,这小 P 又出来捣乱,给小 C 留了个 难题。 给 N 个数,用 a1,a2…an来表示。现在小 P 让小 C 依次取数,第一个数可以 随意取。假使目前取得 aj,下一个数取ak(k>j),则ak必须满足gcd(aj,ak)≥L。 到底要取多少个数呢?自然是越多越好! 不用多说,这不仅是给小 C 的难题,也是给你的难题。

Input

第一行包含两个数N 和 L。 接下来一行,有 N 个数用空格隔开,依次是 a1,a2…an。

Output

仅包含一行一个数,表示按上述取法,最多可以取的数的个数。

Sample Input

5 6
7 16 9 24 6

Sample Output

3

HINT

选取 3个数16、24、6。gcd(16,24)=8,gcd(24,6)=6。

2≤L≤ai≤1 000 000;
30% 的数据N≤1000;
100% 的数据 N≤50 000

Source

 题解:

这种DP根本想不到啊。。。是数论的一般方法还没掌握吗。。。

类似最长上升子序列的做法,只不过有个要求就是gcd必须要>=l,这样根号n枚举因数,然后dp

dp[i]表示以i作为最大公因数可以选的数的最多个数 

满足gcd>=l才更新dp

还是不理解?为什么可以把最大值加到每一个因数上啊?

唉?好像忽然明白了?

i代表若 x 与最后一个选的数gcd==i,此前最多可选多少数,只要要求最后一个选取的数有i因子即可,所以 x 可以更新到 所有 x 的因子。

终于想通了,好开心!

代码:

 1 #include<cstdio>
 2 
 3 #include<cstdlib>
 4 
 5 #include<cmath>
 6 
 7 #include<cstring>
 8 
 9 #include<algorithm>
10 
11 #include<iostream>
12 
13 #include<vector>
14 
15 #include<map>
16 
17 #include<set>
18 
19 #include<queue>
20 
21 #include<string>
22 
23 #define inf 1000000000
24 
25 #define maxn 500+100
26 
27 #define maxm 1000000+100
28 
29 #define eps 1e-10
30 
31 #define ll long long
32 
33 #define pa pair<int,int>
34 
35 #define for0(i,n) for(int i=0;i<=(n);i++)
36 
37 #define for1(i,n) for(int i=1;i<=(n);i++)
38 
39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
40 
41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
42 
43 #define mod 1000000007
44 
45 using namespace std;
46 
47 inline int read()
48 
49 {
50 
51     int x=0,f=1;char ch=getchar();
52 
53     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
54 
55     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
56 
57     return x*f;
58 
59 }
60 int n,m,ans,dp[maxm];
61 
62 int main()
63 
64 {
65 
66     freopen("input2.txt","r",stdin);
67 
68     freopen("output3.txt","w",stdout);
69 
70     n=read();m=read();
71     for1(i,n)
72      {
73         int x=read(),y=0;
74         for1(j,int(sqrt(x)))
75          if(x%j==0)
76          {
77              y=max(y,dp[j]);
78              y=max(y,dp[x/j]);
79          }
80         y++;
81         for1(j,int(sqrt(x)))
82          if(x%j==0)
83          {
84             if(j>=m)dp[j]=y;
85             if(x/j>=m)dp[x/j]=y;
86          }    
87      }
88     for2(i,m,maxm-1)ans=max(ans,dp[i]);
89     printf("%d
",ans);
90 
91     return 0;
92 
93 }
View Code
原文地址:https://www.cnblogs.com/zyfzyf/p/3977852.html