【bzoj1978】【BeiJing2010】取数游戏 game【递推】
2015-04-25 20:40
357 查看
小 C 刚学了辗转相除法,正不亦乐乎,这小 P 又出来捣乱,给小 C 留了个 难题。 给 NN 个数,用 a1,a2,...,ana_1,a_2,...,a_n来表示。现在小 P 让小 C 依次取数,第一个数可以 随意取。假使目前取得 aja_j,下一个数取ak(k>j)a_k(k>j),则aka_k必须满足gcd(aj,ak)≥Lgcd(a_j,a_k)\ge L。 到底要取多少个数呢?自然是越多越好! 不用多说,这不仅是给小 C 的难题,也是给你的难题。
Input
第一行包含两个数NN和LL。接下来一行,有NN个数用空格隔开,依次是 a1,a2,...,ana_1,a_2,...,a_n.
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
本蒟蒻一开始想了一个O(n2logn)O(n^2\log n)的算法:设F[i]表示第i个数取的情况下1到i最多能取几个数,则F[i]=max{F[j]}+1(j<i,gcd(a[j],a[i])≥L)F[i]=\max\left\{F[j]\right\}+1\quad(j
看了hzwer的题解感觉十分精妙……
因为gcd(a[i],a[j])一定是a[i]的约数,所以只用考虑能被a[i]的约数整除的a[j];然后因为这个a[j]肯定是越靠后越好(至少不会比放在前面差),所以设一个last[x]表示数列中所有能被x整除的a[j]中最靠后的那个位置,用数学语言描述就是last[x]=max{j}∣a[j]modx=0,j<i\text{last}[x]=\max\{j\}\mid \;a[j]\mod x=0,j
i是什么呢?F[i]=max{F[last[x]]}+1,满足x∣a[i]且x≥LF[i]=max\{F[last[x]]\}+1,满足 x\mid a[i] 且 x\ge L.
状态数O(n)O(n),转移O(n√)O(\sqrt n),总时间复杂度O(nn√)O(n\sqrt n).
Input
第一行包含两个数NN和LL。接下来一行,有NN个数用空格隔开,依次是 a1,a2,...,ana_1,a_2,...,a_n.
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
本蒟蒻一开始想了一个O(n2logn)O(n^2\log n)的算法:设F[i]表示第i个数取的情况下1到i最多能取几个数,则F[i]=max{F[j]}+1(j<i,gcd(a[j],a[i])≥L)F[i]=\max\left\{F[j]\right\}+1\quad(j
看了hzwer的题解感觉十分精妙……
因为gcd(a[i],a[j])一定是a[i]的约数,所以只用考虑能被a[i]的约数整除的a[j];然后因为这个a[j]肯定是越靠后越好(至少不会比放在前面差),所以设一个last[x]表示数列中所有能被x整除的a[j]中最靠后的那个位置,用数学语言描述就是last[x]=max{j}∣a[j]modx=0,j<i\text{last}[x]=\max\{j\}\mid \;a[j]\mod x=0,j
i是什么呢?F[i]=max{F[last[x]]}+1,满足x∣a[i]且x≥LF[i]=max\{F[last[x]]\}+1,满足 x\mid a[i] 且 x\ge L.
状态数O(n)O(n),转移O(n√)O(\sqrt n),总时间复杂度O(nn√)O(n\sqrt n).
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> using namespace std; const int maxn=50001; int f[maxn]; int last[1000001]; int a[50001]; inline int read(){ int x=0;scanf("%d",&x);return x; } int n,l,ans; int main(){ n=read();l=read(); for(int i=1;i<=n;++i) a[i]=read(); for(int i=1;i<=n;++i){ int &tmp=f[i]; for(int j=1,t=(int)floor(sqrt((double)a[i]));j<=t;++j){ if(a[i]%j) continue; if(j>=l&&f[last[j]]+1>tmp) tmp=f[last[j]]+1; if(a[i]/j>=l&&f[last[a[i]/j]]+1>tmp) tmp=f[last[a[i]/j]]+1; last[j]=i; last[a[i]/j]=i; } if(tmp>ans) ans=tmp; } printf("%d\n",ans); return 0; }
相关文章推荐
- BZOJ 1978: [BeiJing2010]取数游戏 game( dp )
- BZOJ 1978: [BeiJing2010]取数游戏 game
- BZOJ1978: [BeiJing2010]取数游戏 game
- 【BZOJ 1978】 [BeiJing2010]取数游戏 game
- bzoj 1978: [BeiJing2010]取数游戏 game -- dp
- bzoj 1978: [BeiJing2010]取数游戏 game 数学
- 1978: [BeiJing2010]取数游戏 game
- bzoj1978 [BeiJing2010]取数游戏 game DP
- BZOJ1978 [BeiJing2010]取数游戏 建图+拓扑序
- 【bzoj1978】 BEIJING2010 取数游戏 game dp优化
- BZOJ1978: [BeiJing2010]取数游戏 game
- bzoj 1977: [BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
- bzoj1874 [BeiJing2009 WinterCamp]取石子游戏 nim游戏 sg函数
- bzoj 1854: [Scoi2010]游戏(二分图的最大匹配)
- bzoj1854 [Scoi2010]游戏(并查集)
- bzoj2091[Poi2010]The Minima Game DP
- BZOJ1977: [BeiJing2010组队]次小生成树 Tree
- 【POI2010】【BZOJ2091】The Minima Game
- bzoj1854[Scoi2010] 游戏
- 【bzoj2000】[Hnoi2010]stone 取石头游戏