思路:
- 思路比较好想
- 除法变乘法, 从小到大枚举 a中没有出现过的k, 对每一个数看他 ai*k--ai*(k+1)-1, 中间是否有数 (用树状数组维护即可) 这里用前缀和查询就可以O1
- 当 ai*k> c break即可
- 发现描述的过程就是调和级数nlogn 复杂度,
- 注意这里 n和c的 和 都是 1e6, 就不要2个数一起枚举, 选择一个就可以了
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 2000005 int n,m; int T; long long p[M]; int val[M]; int qu(int a) { int ans=0; while(a>=1) /// { ans+=val[a]; a-=a&(-a); } return ans; } void add(int a) { while(a<=m) { val[a]++; a+=a&(-a); } } int vis[M]; int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>T; while(T--) { cin>>n>>m; for(ri i=1;i<=m;i++) vis[i]=0,val[i]=0; for(ri i=1;i<=n;i++) { cin>>p[i]; vis[p[i]]=1; add(p[i]); } int flag=0; for(ri i=1;i<=m;i++) { if(vis[i]==0) { for(ri j=1;j<=m;j++) { long long a=1ll*j*i; if(a>m) break; if(vis[j]==0) continue; long long b=1ll*j*(1ll*i+1)-1; if(b>m) b=m; int tmp=qu(b)-qu(a-1); if(tmp) { flag=1; break; } } } if(flag) break; } if(flag) cout<<"No"<<"\n"; else cout<<"Yes"<<"\n"; } return 0; }
后记:
- 查询区间是否存在问题: 只有查询就 前缀和, 只有修改就 差分, 都有就 树状数组.
- 调和级数 关键就是: x1,x2,x3... 且范围不超过n, 或者 /1, /2,/3....
- a*(b*c), 1ll 不要只写在外面, 会优先算括号里面的, 1ll*a*(1ll*a*b)