题目链接:https://cn.vjudge.net/problem/HDU-6287
题目大意:每个问题给出三个正整数l,r,dl,r,d,小Q需要通过口算快速判断al×al+1×...×ar−1×aral×al+1×...×ar−1×ar是不是d的倍数。
题目思路:如果暴力求解(al+...+ar)/d,数据内存肯定会超,所以数据肯定是要分解成因子判断的
思路一:先定义一个数组存不大于100000的素数,然后存al到ar每个元素所含有的素数次数,d肯定可以分解成m个素数相乘,那我们只需判断这m个素数j的次数是否不大于之前存的素数j的次数
代码:之前写了,找不到了。。。。结果是超时,思路可以解决问题,但是超时是解决不了的
正确思路:二分+vector二维数组
p[因子][元素a下标]
使用二维vector,n行m列,n是a[h]的因子个数,m存的是含因子i的a[h]元素下标j
比较d的每个因子,因子次数不大于a[l]到a[r]这因子个数总和
a[l]到a[r]这因子个数总和,我们可以用二分查找求得,vector的p[因子][元素a下标], lower_bound(p[i].begin(), p[i].end(), l)p[i]就是存因子i的二维数组,就是查找l的下标
upper_bound(p[i].begin(), p[i].end(), r)- lower_bound(p[i].begin(), p[i].end(), l)---------------这是查找区间[l,r]元素个数的正确姿势
代码:
#include<iostream> #include<algorithm> #include<vector> using namespace std; vector<int> p[100005]; void shuru(int x,int i) { for(int j=2;j*j<=x;j++) { while(x%j==0) { x/=j; p[j].push_back(i);//因子j,i下标 } } if(x>1) //x可能是2,3 p[x].push_back(i); } bool solve(int l,int r,int d) { int cnt; for(int i=2;i*i<=d;i++) { cnt=0; while(d%i==0) { d=d/i; cnt++; } if(cnt>0&&upper_bound(p[i].begin(),p[i].end(),r)-lower_bound(p[i].begin(),p[i].end(),l)<cnt)//区间l,r含因子i的个数 { return 0; } } if(d>1&&upper_bound(p[d].begin(),p[d].end(),r)-lower_bound(p[d].begin(),p[d].end(),l)==0) //d可能是2,3 return 0; return 1; } int main() { int T; scanf("%d",&T); while(T--) { int n,m,l,r,d; for(int i=0;i<100005;i++) p[i].clear(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); shuru(x,i); } for(int i=1;i<=m;i++) { scanf("%d%d%d",&l,&r,&d); if(solve(l,r,d)) printf("Yes\n"); else printf("No\n"); } } }
总结:vector存元素注意存元素为0的情况,因为vector的元素大小也是默认为0 ,如果没注意,可能会因此产生错误。
比如该题,用a数组的下标存入vector二维数组中,既然下标要存入,那我们就设下标从一开始!!!