[思路题] hdu 5288 OO’s Sequence

本文探讨了一道复杂的算法题目,该题目要求将一组数字划分为多个区间,并从中选取尽可能多的数,使得每个选中的数在对应的区间内没有其他数是它的因数。文章详细介绍了题目的解法,包括如何通过预处理和逆向思考来优化算法,最终给出了一种时间复杂度为(O(nsqrt{n}

题意:

非常纠结的题意。

其实是把这n个数分成若干个长度任意的连续区间。

对于每个区间,取一个数,如果这个区间里剩下的数中没有一个数是这个数的约数。

那么说明这个数可取。

问你对于所有的区间,一共能取多少个数。

思路:

类似的计算方式。

比如 5 4 1 2 3 这5个数

看成

5

5 4

4

5 4 1

4 1

1

5 4 1 (2)

4 1 (2)

1 (2)

2

...

先过一遍保证后面的数不能是前面的数的倍数。

这么遍历的时候其实就是看当前这个数的约数是否在前面的数中出现过(sqrt(ai)的复杂度)

然后把这个数放上去,顺便标记。

就比如第四个数2,本来可以放4次,但是由于1在其前面距离1的位置,所有3个都不能放了,只能放一个。

然后这样的会出现一个情况,就是放的数是之前数的约数。

这样的话就从右往左再过一遍。

把放的次数给减掉。

比如对于4

他距离1有一个单位的距离,放4的时候放了2个,那么其实就是多放了1到末尾这么多次的2个。

减掉就好了。

所有最后的复杂度是(2*n*sqrt(n))。

代码:

#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"cmath"
#include"map"
#include"vector"
#include"string"
using namespace std;
#define ll __int64
ll mod=1000000000+7;
int v[123456],mp[12345];
int kx[123456];
int main()
{
    int n;
    while(scanf("%d",&n)!=-1)
    {
        memset(mp,0,sizeof(mp));
        for(int i=1; i<=n; i++) scanf("%d",&v[i]);
        ll ans=0,sum=0;
        for(int i=1; i<=n; i++)
        {
            int tep=0,lit=sqrt(v[i]*1.0);
            for(int j=1; j<=lit; j++)
            {
                if(v[i]%j==0)
                {
                    tep=max(tep,mp[j]);
                    tep=max(tep,mp[v[i]/j]);
                }
            }
            sum=sum+((i-tep))%mod;
            kx[i]=i-tep;
            ans=(ans+sum)%mod;
            mp[v[i]]=i;
            // printf("%I64d %I64d\n",sum,ans);
        }

        for(int i=0; i<=10000; i++) mp[i]=n+1;
        sum=0;
        for(int i=n; i>=1; i--)
        {
            int tep=n+1,lit=sqrt(v[i]*1.0);
            for(int j=1; j<=lit; j++)
            {
                if(v[i]%j==0)
                {
                    tep=min(tep,mp[j]);
                    tep=min(tep,mp[v[i]/j]);
                }
            }
                    if(tep!=n+1)
                        sum=(sum+kx[i]*(n+1-tep))%mod;
            mp[v[i]]=i;
        }
        printf("%I64d\n",((ans-sum)%mod+mod)%mod);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值