杭电5288如何查找一个数字的最左边因子和最右边因子的下标,先处理100以下的数字,100以上的数字则是sqrt(n)
来源:互联网 发布:小黄车密码锁破解软件 编辑:程序博客网 时间:2024/05/17 10:38
对于区间问题,一般统计满足区间的区间对结果的贡献值为多少,这个题就可以统计每个数字的因子的左右最近的值得下标
l[i],r[i],则这个数字对答案的贡献值为(i-l[i])*(r[i]-i),这个题o(n*n)的算法显然不行,于是看到输入数据为10000从这里下手,
先处理1~100,按照先输入的必在后输入的前面的关系,正向扫描统计l[i],同时反向扫描统计r[i],然后按照ai的倍数关系,
由于现在ai>100且第二层循环是按照ai的倍数递增的,所以总的时间为O(n^sqrt(n)),由于提前储存了每个数出现的下标,
而且先存入的坐标肯定在后存入的前面,所以就按照倍数关系正向扫描,起初的下标必定小于i,所以更新他们的左边因子,
同理反向更新右边因子。
#include<iostream>#include<cstdio>#include<cstring>#include<cctype>#include<cstdlib>#include<cctype>#include<string>#include<set>#include<map>#include<vector>#include<algorithm>using namespace std;#define LL long longconst LL mod=1e9+7;const int N=1e5+10;int a[N],p[N],l[N],r[N];vector<int> vec[N];int main(){ LL n; while(cin>>n) { for(int i=101;i<=10000;i++) vec[i].clear(); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); l[i]=0; r[i]=n+1; if(a[i]>100) vec[a[i]].push_back(i); } for(int j=1;j<=100;j++) { int tem=0; for(int i=1;i<=n;i++) { if(a[i]%j==0) l[i]=max(l[i],tem); if(a[i]==j) tem=i; } tem=n+1; for(int i=n;i>0;i--) { if(a[i]%j==0) r[i]=min(r[i],tem); if(a[i]==j) tem=i; } } memset(p,0,sizeof(p)); for(int i=1;i<=n;i++) { if(a[i]>100) { for(int j=a[i];j<=10000;j+=a[i]) { while(p[j]<vec[j].size()&&vec[j][p[j]]<i) { r[vec[j][p[j]]]=min(r[vec[j][p[j]]],i); if(p[j]<vec[j].size()-1&&(vec[j][p[j]+1]<i)) p[j]++; else break; } } } } for(int i=10000;i>=101;i--) p[i]=vec[i].size()-1; for(int i=n;i>0;i--) { if(a[i]>100) { for(int j=a[i];j<=10000;j+=a[i]) { while(p[j]>=0&&vec[j][p[j]]>i) { l[vec[j][p[j]]]=max(l[vec[j][p[j]]],i); if(p[j]>0&&vec[j][p[j]-1]>i) p[j]--; else break; } } } } LL sum=0; for(int i=1;i<=n;i++) sum=(sum+((i-l[i])*(r[i]-i))%mod)%mod; cout<<sum<<endl; } return 0;}
0 0
- 杭电5288如何查找一个数字的最左边因子和最右边因子的下标,先处理100以下的数字,100以上的数字则是sqrt(n)
- 数字的因子和
- N^N 数字的最右边
- 求n^n和n!的最左边的数字
- 求n^n和n!的最左边的数字
- HDU 1060 1061求 n^n 最左边 最右边的数字
- acm课-求n^n的最左边的数字
- N的M次方最右边的数字
- Problem F: 最右边的数字
- 将一个字符串中小于0的数字放到左边,大于0的数字放到右边
- 获取数字特定因子元素的个数
- 筛选求数字不包括自身的因子和
- LightOJ 1336 Sigma Function(1--n中所有因子和为偶数的数字个数)
- (HDU1061||nefu783)&&nefu 66 求N^N的最右边和最左边的数
- N的因子和
- 世界上最神奇的数字是:142857
- 世界上最神奇的数字是142857
- 世界上最神奇的数字是: 142857
- 【整理】详解Python中re.sub
- 离散化/分箱/分组(Discretization / binning / Interactive grouping)
- HDOJ 2502 月之数
- linux环境为java修改环境变量
- ARM-1.1-arm家族
- 杭电5288如何查找一个数字的最左边因子和最右边因子的下标,先处理100以下的数字,100以上的数字则是sqrt(n)
- Android 按照比例剪裁图片,以及拍照并剪裁
- HDOJ 2017 字符串统计
- LeetCode(40) Combination Sum II
- 开门人和关门人
- 通知Notification
- Android开发之获取相册照片和获取拍照照片
- 评委会打分
- hdu5045Contest 概率dp