hdu5288 vector用法+ ……(多校1.1)

13 篇文章 0 订阅

题目大意:给定一个序列含有n个数,定义f(l,r) = l  ~r序列中没有因子的数的个数 ,求n个数的序列中所有的连续子序列的f和。对1000000007取模

思路:定义数组l , r .l[i] , r[i] 分别表示第i个元素左边最近因子的位置和右边最近的因子的位置。则第i个数贡献的f值为(i - l[i]) * (r[i] - i )。

在求l 和r的过程中,肯定不能每个因子都去遍历着找,必然会超时。首先,一个数a的因子必然在sqrt(a)内能找到,所以只需要枚举从sqrt(a)到1所有的因子,找到最近的一个l和r

即可。然后就是如何尽快的找到因子所在的位置,刚才说了,肯定不能去遍历,不然必然超时,如何用元素来确定他的下标?就想到了STL里面的vector,可以开10000个vector,

就定义为vector<int > v[10000],然后输入a[i]时。只需要v[a[i]].push_back(i)即可,然后查找的时候遍历即可,其实和hash思想差不多。

另外强调一点,x是y的因子,则y/x也是y的因子,y/x比一定小于sqrt(y)!!

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>


using namespace std;
#define MAXN 100005
#define MOD 1000000007
int a[MAXN] , l[MAXN] , r[MAXN];
int load[10005];
vector<int> v[10005];
vector<int>::iterator it;
int n;


void slove(int pos)
{
    int num = (int)sqrt(a[pos]);
    if(num * num != a[pos]) num ++;
    int maxl = 0;
    int minr = n + 1;
    for(int i = num  ; i > 0 ; i --)
    {
        if(a[pos] % i != 0) continue;   //若不是因子,直接下一个
        int res = a[pos] / i;       //是因子 , 则要找到他的另一个因子,一起判断
        for(int j = 0; j < v[i].size() ; j ++ )
        {
            if(v[i][j] < pos) maxl = max (maxl , v[i][j]);
            if(v[i][j] > pos) minr = min (minr , v[i][j]);
        }
        for(int j = 0; j < v[res].size() ; j ++ )
        {
            if(v[res][j] < pos) maxl = max (maxl , v[res][j]);
            if(v[res][j] > pos) minr = min (minr , v[res][j]);
        }
    }
    l[pos] = maxl;
    r[pos] = minr;
    return ;
}


int main()
{
    while(scanf("%d" , &n) != EOF)
    {
        memset(l , 0 , sizeof(l));
        memset(r , 0 , sizeof(r));
        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);       //记录每个数字的位置
        }
        for(int i = 1 ; i <= n ; i ++ )
        {
            slove(i);      //找到l,r
        }
        int sum = 0;
        for(int i = 1 ; i <= n ; i ++ )
        {
            sum = (sum + (i - l[i])*(r[i] - i) % MOD ) % MOD;
        }
        cout << sum << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值