bzoj 1978: [BeiJing2010]取数游戏 game 数学

来源:互联网 发布:最好的电视直播软件 编辑:程序博客网 时间:2024/06/07 05:15

题意

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

分析

考虑dp,设f[i]表示从i开始往后取的最大方案,t[x]表示从x这个数往后取的最大方案。
对于f[i],枚举gcd(a[i],a[j])=d>=L,用t[d]+1来更新f[i]。
然后枚举所有f[i]的约数x,用f[i]来更新t[x]即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=50005;int n,m,a[N],f[N],t[1000005];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int main(){    n=read();m=read();    for (int i=1;i<=n;i++) a[i]=read();    int ans=0;    for (int i=n;i>=1;i--)    {        for (int j=1;j*j<=a[i];j++)            if (a[i]%j==0)            {                if (j>=m) f[i]=max(f[i],t[j]+1);                if (a[i]/j>=m) f[i]=max(f[i],t[a[i]/j]+1);            }        for (int j=1;j*j<=a[i];j++)            if (a[i]%j==0) t[j]=max(t[j],f[i]),t[a[i]/j]=max(t[a[i]/j],f[i]);        ans=max(ans,f[i]);    }    printf("%d",ans);    return 0;}
原创粉丝点击