据说是简单题,可是对于我这种菜比却怎么想也没有想到,后来看了题解才明白,原来我一直把区间理解错了,看来敲题之前还真的不能玩游戏。
题意:给你几个数字,找出所有区间的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);
}
}