HDU5288 OO’s Sequence

多校第一场就爆零了,蛤蛤蛤蛤蛤。。。。

题目大意:给一个数组a,f(i,j)表示ai到aj之间存在(这样的数)的个数,(这样的数)就是它不可以整除这个区间内其他的数,求数组a的所有的区间[i,j](这样的数)的个数之和。

思路:对ai,找到ai左边离它最近的和右边离它最近的可以被它整除的数,并用l[i],r[i]记录它们的位置,那么在包含ai的集合中,ai是(这样的数)的次数ans[i]=(i-l[i])*(r[i]-i),然后把所有的ans[i]加起来即为结果,比赛的时候已经想到了这一步,然而并没有什么卵用。l[i]和r[i]的求法具体看代码注释。

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<ctime>
#define mx 100005
#define LL long long 
#define mod 1000000007
#define esp 1e-6
#define y1 y1234
#define INF 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 200005
const double PI = acos(-1.0);
using namespace std;

int n, a[mx];
int l[mx], r[mx];
int pre[mx];        //pre[k]表示k在数组中的位置
vector<int>f[mx];   //f[k]记录k的因数

void init(){
	for (int i = 1; i < 10001; i++){
		for (int j = i; j < 10001; j += i){
			f[j].push_back(i);
		} 
	}
	return;
}

int main(){    
	init();
	while (scanf("%d", &n) != EOF){
		memset(pre, -1, sizeof pre);
		for (int i = 1; i <= n; i++){      //正向扫描数组l[i]
			scanf("%d", &a[i]);
			int ma = 0;
			for (int j = 0; j < f[a[i]].size(); ++j){     //遍历a[i]的所有因数
				int v = f[a[i]][j];
				if (pre[v] != -1)            //如果a[i]的因数v出现在数组a中
					ma = max(ma, pre[v]);    //比较上一个出现在数组a中的因数和v哪个离a[i]比较近,更新ma
			}
			l[i] = ma;                 
			pre[a[i]] = i;                   //更新pre数组
		}
		memset(pre, -1, sizeof pre);
		for (int i = n; i >= 1; i--){       //同理反向扫描数组求r[i]
			int mi = n + 1;
			for (int j = 0; j < f[a[i]].size(); ++j){
				int v = f[a[i]][j];
				if (pre[v] != -1)mi = min(mi, pre[v]);
			}
			r[i] = mi;
			pre[a[i]] = i;
		}
		
		LL ans = 0;
		for (int i = 1; i <= n; i++){
			LL x = i - l[i];
			LL y = r[i] - i;
			ans = ans + (x*y) % mod;
		}
		cout << ans%mod << endl;
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值