Integral Array (转化思想:除法->乘法+ 调和级数 +前缀和查询区间是否有数(无修改)) (T个测试时,有2个的那个综合都是N时)

 

思路: 

  • 思路比较好想
  •  除法变乘法,  从小到大枚举 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;
    
} 
View Code

后记:

  • 查询区间是否存在问题: 只有查询就 前缀和, 只有修改就 差分, 都有就 树状数组.
  • 调和级数 关键就是: x1,x2,x3... 且范围不超过n, 或者 /1, /2,/3.... 
  • a*(b*c), 1ll 不要只写在外面, 会优先算括号里面的, 1ll*a*(1ll*a*b)                              

 

posted @ 2022-11-02 14:56  VxiaohuanV  阅读(36)  评论(0编辑  收藏  举报