HDU 5288 OO’s Sequence (数论 + 思维)

13 篇文章 0 订阅
9 篇文章 0 订阅

OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there’s no j(l<=j<=r,j<>i) satisfy ai%aj=0 ,now OO want to know Σni=1Σnj=if(i,j) mod (109+7) .

There are multiple test cases. Please process till EOF.
In each test case:
First line: an integer n(n<=10^5) indicating the size of array
Second line:contain n numbers ai (0< ai <=10000)

题意

f(l,r) 被定义为满足下列条件的 ai 的个数: li,jr , ij 且不存在 ai % aj=0

Σni=1Σnj=if(i,j) mod (109+7)

解题思路

此题可等价的视作:每个 ai 对结果 ans 的贡献,若对于 ai 所能满足的最大区间已知 [l,r] ,则贡献为 (il+1)×(ri+1)

在 n 个数中,能使得 ai 满足 ai % aj=0 aj 必须是 ai 的约数。

故统计每个值的出现位置,通过大小为 10000 的向量组保存,v[ ai ] 向量保存所有值等于 ai 的数是位置。

对于每个 ai ,枚举其约数,对其所有的约数 aj 出现的位置 j 进行判断:

  • 以大于 i 的最小 j 作为 ai 最大区间的右边界
  • 以小于 i 的最大 j 作为 ai 最大区间的左边界

代码

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 100000 + 10;
int n, a[N], l[N], r[N];
vector<int> v[10010];
void solve(int x)
{
    int val = a[x];
    int sqr = sqrt(val + 0.5);
    for(int i=1;i<=sqr;i++)
    {
        if(val % i)    continue;
        for(int idx = 0, cur = i;idx<2;idx++)
        {    
            for(int j=0;j<v[cur].size();j++)
            {
                //printf("v[%d][%d] = %d\n", cur, j, v[cur][j]);
                if(v[cur][j] < x)
                    l[x] = max(l[x], v[cur][j]+1);
                if(v[cur][j] > x)
                    r[x] = min(r[x], v[cur][j]-1);
            }
            cur = val / i;
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=10000;i++)
            v[i].clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            v[a[i]].push_back(i);
        }
        long long ans = 0;
        for(int i=1;i<=n;i++)
        {
            l[i] = 1;    r[i] = n;
            solve(i);
            (ans += (long long)(i-l[i]+1)*(r[i]-i+1)%mod) %= mod;
        }
        printf("%lld\n", ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值