hdu5288 多校联合第一场第一题

据说是简单题,可是对于我这种菜比却怎么想也没有想到,后来看了题解才明白,原来我一直把区间理解错了,看来敲题之前还真的不能玩游戏。
题意:给你几个数字,找出所有区间的f(i,j)之和,其中i,j代表位置,我一直以为是数字。。。
假如有5个数1 2 6 3 4,那么f(2,3)就是2和6这两个数字的f值,结果为1,一开始我以为f(2,3)就是从2一直到6,就是2 3 4 5 6有几个没有因子的数字。
既然看懂了题意,就懂得了怎么去解,一个数字所能贡献的答案就是从这个数字开始,直到左边第一个因数之间有几个数字乘以从这个数字开始,到右边第一个因数之间有几个数字的积,因为如果区间超过这个范围,那么这个数字就是有因数的,就不算在f(i,j)里面了,那么在这个范围里面区间(要求包括这个数字,区间的左端点在这个数字左边,右端点在这个区间的右边)的个数就是这个数字所贡献的答案。
设一个l[i],r[i]分别计算这个区间左右第一个因子的位置,直接暴力求l[i],r[i],果断TLE。
正解:因为数字最大为10000,开一个vector,记录每个数字出现的位置,然后从1到100枚举每一个数,如果是a[i]的因子,那么去vector[a[i]]里面找这个数字的位置,如果比l[i]大,并且比i小,更新l[i],如果比r[i]小,比i大,更新r[i],注意还要计算与这个因子相乘正好等于a[i]的数字,做以上操作
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define maxn 100010
#define mod 1000000007
using namespace std;
int l[maxn],r[maxn];     //记录左边和右边最靠近i且能被a[i]整除的数字的位置
int a[maxn];
vector<int> vec[maxn];    //记录每个数出现的位置
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        long long ans = 0;
        for(int i = 0; i < maxn; i++)   //清空初始化
            vec[i].clear();
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            l[i] = 0;                  //初始化l[i]为0,r[i]为n+1
            r[i] = n+1;
            vec[a[i]].push_back(i);    //存放位置
        }
        for(int i = 1; i <= n; i++)
        {
            int m = sqrt(a[i]) + 1;
            for(int j = 1; j <= m; j++)
            {
                if(a[i]%j == 0)
                {
                    int tem = a[i]/j;
                    for(int k = 0; k < vec[j].size(); k++)
                    {
                        if(vec[j][k] < i&&vec[j][k] > l[i])
                            l[i] = vec[j][k];
                        if(vec[j][k] > i&&vec[j][k] < r[i])
                            r[i] = vec[j][k];
                    }
                    for(int k = 0; k < vec[tem].size(); k++)
                    {
                        if(vec[tem][k] < i&&vec[tem][k] > l[i])
                            l[i] = vec[tem][k];
                        if(vec[tem][k] > i&&vec[tem][k] < r[i])
                            r[i] = vec[tem][k];
                    }
                }
            }
        }
        for(int i = 1; i <= n; i++)
        {
            ans += (r[i] - i)*(i - l[i]);
            ans = ans%mod;
        }
        printf("%lld\n",ans);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值