hdu 5288 OO’s Sequence 枚举因数

题意:给出n个数a【1】~a【n】,问里面有多少个区间满足:对于该区间内任意一个数,区间内没有任何数能被其整除。

首先预处理出所有数的因子(1~10000),然后枚举每个数a【i】的因子,对于每个因子找出其在i左边和右边最靠近i的位置,l, r,那么这个数的贡献就是(i-l+1)*(r-i+1).注意要%mod

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cmath>
#include <time.h>
#include <vector>
#include <cstdio>
#include <string>
#include <iomanip>
///cout << fixed << setprecision(13) << (double) x << endl;
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
#define Mp(a, b) make_pair(a, b)
#define asd puts("asdasdasdasdasdf");
typedef long long ll;
//typedef __int64 LL;
const int inf = 0x3f3f3f3f;
const int N = 100010;
const int mod = 1e9+7;

int n;
int a[N];
vector <int> yue[N];    //每个数的约数
vector <int> pos[N];    //每个约数出现的位置

int main()
{
    for( int i = 1; i <= 10000; ++i ) {
        yue[i].clear();
        for( int j = 1; j * j <= i; ++j ) {
            if( i % j == 0 ) {
                yue[i].push_back(j);
                if( i / j != j )
                    yue[i].push_back(i/j);
            }
        }
    }
    while( ~scanf("%d", &n) ) {
    	for( int i = 1; i <= 100000; ++i )
    		pos[i].clear();
        for( int i = 1; i <= n; ++i ) {
            scanf("%d", &a[i]);
            pos[a[i]].push_back(i);
        }
        ll ans = 0;
        for( int i = 1; i <= n; ++i ) {
            ll l = 1, r = n;
            int sz = yue[a[i]].size();
            for( int j = 0; j < sz; ++j ) {
                int x = yue[a[i]][j];    //x为a[i]的约数
                int siz = pos[x].size();
                if( siz == 0 )
                    continue;
                if( pos[x][siz-1] <= i ) {    //所有数在i左边
                	if( pos[x][siz-1] < i )
                		l = max( l, 1LL*pos[x][siz-1]+1 );
					else {
						if( siz >= 2 )
							l = max( l, 1LL*pos[x][siz-2]+1 );
					}
					continue;
                }
                if( pos[x][0] >= i ) {    //在i右边
                	if( pos[x][0] > i )
                        r = min( r, 1LL*pos[x][0]-1 );
					else {
						if( siz >= 2 )
							r = min( r, 1LL*pos[x][1]-1 );
					}
                    continue;
                }
				else {	//在i两边
					int pp = lower_bound( pos[x].begin(), pos[x].end(), i )- pos[x].begin();
					l = max( l, 1LL*pos[x][pp-1]+1 );
					if( pos[x][pp] == i )
						pp++;
					//if( pp < siz )
					r = min( r, 1LL*pos[x][pp]-1 );
				}
			}
            ans += 1LL*(1LL*i-l+1) * (r-1LL*i+1) % mod;
            ans %= mod;
        }
        printf("%lld\n", ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值