【多校第一场】【筛法改】HDU 5288 OO’s Sequence

这道题的数据范围需要让我们有些反应才是,虽然n的组数是1e5的大小,但是数字的范围是1e4。


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5288


思路是找到每一个元素的左端首个因数的位置和右端因数的位置,这是显而易见的。但是这题的问题却不是在这里,而是在于如何操作。学长介绍的方法是将他们从小到大排列,然后去寻找当前值的倍数。。。有点说不太清不过对着代码模拟一遍一个就好,注释才是正文系列。


记住,long long不要乱开,sort时记得你的数组是从哪开始的。(因为这些而WA了一天TAT)。


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define LL long long
using namespace std;

struct n
{
    int num;
    int id;
}num[1000100];
LL ans;
const int mod=1e9+7;
vector <int>lr[10002];

bool cmp(n a,n b)
{
    return a.num<b.num;
}

int main()
{
    int n;
	while(~scanf("%d",&n))
	{
	    for(int i=0;i<=10001;i++)
            lr[i].clear();
        ans=0;
	    for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i].num);
            num[i].id=i;
        }

        sort(num+1,num+n+1,cmp);

        int k=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=num[i].num;j<=10000;j+=num[i].num)
            {
                lr[j].push_back(num[i].id);
            }
            if(i!=n && num[i].num==num[i+1].num) continue;

            while(k<=i)
            {
                int l=0,r=n+1;
                for(int j=0;j<lr[num[k].num].size();j++)
                {
                    if(lr[num[k].num][j]<num[k].id && lr[num[k].num][j]>l)
                    {
                        l=lr[num[k].num][j];
                    }
                    else if(lr[num[k].num][j]>num[k].id && lr[num[k].num][j]<r)
                    {
                        r=lr[num[k].num][j];
                    }
                }
                ans=(ans+(num[k].id-l)*(r-num[k].id))%mod;
                k++;
//                cout<<l<<" "<<r<<" "<<ans<<endl;
//                for(int i=1;i<=n;i++)
//                {
//                    printf("%d  |",lr[i].size());
//                    for(int j=0;j<lr[i].size();j++) printf(" %d",lr[i][j]);
//                    printf("\n");
//                }
            }
        }

//        for(int i=1;i<=n;i++)
//        {
//            printf("%d  |",lr[i].size());
//            for(int j=0;j<lr[i].size();j++) printf(" %d",lr[i][j]);
//            printf("\n");
//        }

        printf("%lld\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值