标签:这一 thml open ret pac www ssis 次数 names
Input第一行包含一个正整数T(1≤T≤10)T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含两个正整数n,m(1≤n,m≤100000)n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含nn个正整数a1,a2,...,an(1≤ai≤100000)a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来mm行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000)l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。Output对于每个问题输出一行,若是倍数,输出Yes,否则输出No。Sample Input
1 5 4 6 4 7 2 5 1 2 24 1 3 18 2 5 17 3 5 35
Sample Output
Yes No No Yes
思路参考链接:https://blog.csdn.net/wjmwsgj/article/details/80519183
对于一个数(k)是不是d的倍数这类问题,我们可以对这两个数分解质因数,之后看看k的质因数和d的质因数之间的关系,如果满足对于d的每一个质因数个数,在k中都有出现过,且k的出现次数要大于等于d的出现次数,这个就是满足的,举个例子,36 和 6 ,36的质因数有 2,2,3,3,6的质因数有 2,3,其中36中2出现的次数大于了6中2出现的次数,36中3出现的次数大于了6中3出现的次数,故36是6的倍数。
那么对于这道题,我们需要做的就是先将这n个数分解质因数,对于区间问题我们要怎么解决呢?我们把质因数出现的位置给存下来,比如说我们现在在第3个数,a[3] = 8 ,那么我们开一个vector w[2]里加入 3,3,3,3,(相当于w[2]里面记录的是2这个质因子是下标为2这个数的因子)之后,之后比如说我们现在要查询l,r的区间是不是d的倍数,我们将d分解质因数之后用二分去查询我们当前的区间里有没有这个值就好了。
刚开始用的质因子分解方法复杂度太大,导致TLE
1 const int maxn=100005; 2 vector<int>w[maxn]; 3 int maxx=0; 4 bool isprim(int x) 5 { 6 for(int i=2; i<=sqrt(x); ++i) 7 { 8 if(x%i==0) return 0; 9 } 10 return 1; 11 } 12 void digui(int x,int id) 13 { 14 int temp=sqrt(x); 15 if(isprim(x)) 16 w[x].push_back(id),maxx=max(maxx,x); 17 else 18 { 19 for(int i=2; i<=temp; ++i) //这个for循环作用就是找一个x的因子 20 { 21 if(x%i==0) 22 { 23 digui(i,id); 24 digui(x/i,id); 25 } 26 } 27 } 28 }
TLE全部代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<math.h> 6 #include<vector> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=100005; 10 vector<int>w[maxn]; 11 int maxx=0; 12 bool isprim(int x) 13 { 14 for(int i=2; i<=sqrt(x); ++i) 15 { 16 if(x%i==0) return 0; 17 } 18 return 1; 19 } 20 void digui(int x,int id) 21 { 22 int temp=sqrt(x); 23 if(isprim(x)) 24 w[x].push_back(id),maxx=max(maxx,x); 25 else 26 { 27 for(int i=2; i<=temp; ++i) //这个for循环作用就是找一个x的因子 28 { 29 if(x%i==0) 30 { 31 digui(i,id); 32 digui(x/i,id); 33 } 34 } 35 } 36 } 37 int main() 38 { 39 int t; 40 scanf("%d",&t); 41 while(t--) 42 { 43 maxx=0; 44 int n,m; 45 scanf("%d%d",&n,&m); 46 for(int i=0;i<maxn;i++) 47 w[i].clear(); 48 for(int i=0;i<n;++i) 49 { 50 int x; 51 scanf("%d",&x); 52 digui(x,i); 53 } 54 // for(int i=0;i<maxx;i++) 55 // sort(w,w+w[i].size()); 56 while(m--) 57 { 58 int flag=0,l,r,d; 59 scanf("%d%d%d",&l,&r,&d); 60 l--,r--; 61 for(int i=2;i<=sqrt(d);++i) 62 { 63 int num=0; 64 while(d%i==0) 65 d/=i,num++; 66 if(num) 67 { 68 int pos=upper_bound(w[i].begin(),w[i].end(),r)-lower_bound(w[i].begin() , w[i].end(),l); 69 if(pos < num) //如果小于我们现在需要的,就说明不行。 70 { 71 flag=1; 72 break; 73 } 74 } 75 } 76 if(d>1) //同理 77 { 78 int pos=upper_bound(w[d].begin(),w[d].end(),r)-lower_bound(w[d].begin() , w[d].end(),l); 79 if(pos==0) flag=1; 80 } 81 if(flag) 82 { 83 printf("No\n"); 84 } 85 else 86 { 87 printf("Yes\n"); 88 } 89 } 90 } 91 return 0; 92 }
实际上不需要用isprim来判断某个数是不是素数
看下面一种方法:
1 const int maxn=100005; 2 vector<int>w[maxn]; 3 int maxx=0; 4 void resolve(int x,int id) 5 { 6 for(int i = 2 ; i * i <= x ; i++) // 这里的i最大是313 7 { 8 while(x % i == 0) //一直除的话就不会遇到i是合数的情况 9 { 10 w[i].push_back(id); 11 x = x/i; 12 } 13 } 14 if(x>1) // 这里有一个问题就是 我sqrt(maxn)里的最大的质数其实是313,那么我来了一个2 * 313的时候,我们找到的质因数只有2 ,所以当他没有到1的时候说明我们没有完 15 { 16 w[x].push_back(id); // 需要在搞一下 17 } 18 }
正确代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<math.h> 6 #include<vector> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=100005; 10 vector<int>w[maxn]; 11 int maxx=0; 12 void resolve(int x,int id) 13 { 14 for(int i = 2 ; i * i <= x ; i++) // 这里的i最大是313 15 { 16 while(x % i == 0) //一直除的话就不会遇到i是合数的情况 17 { 18 w[i].push_back(id); 19 x = x/i; 20 } 21 } 22 if(x>1) // 这里有一个问题就是 我sqrt(maxn)里的最大的质数其实是313,那么我来了一个2 * 313的时候,我们找到的质因数只有2 ,所以当他没有到1的时候说明我们没有完 23 { 24 w[x].push_back(id); // 需要在搞一下 25 } 26 } 27 /*这一种质因数分解太耗时了*/ 28 //bool isprim(int x) 29 //{ 30 // for(int i=2; i<=sqrt(x); ++i) 31 // { 32 // if(x%i==0) return 0; 33 // } 34 // return 1; 35 //} 36 //void digui(int x,int id) 37 //{ 38 // int temp=sqrt(x); 39 // if(isprim(x)) 40 // w[x].push_back(id),maxx=max(maxx,x); 41 // else 42 // { 43 // for(int i=2; i<=temp; ++i) //这个for循环作用就是找一个x的因子 44 // { 45 // if(x%i==0) 46 // { 47 // digui(i,id); 48 // digui(x/i,id); 49 // } 50 // } 51 // } 52 //} 53 int main() 54 { 55 int t; 56 scanf("%d",&t); 57 while(t--) 58 { 59 maxx=0; 60 int n,m; 61 scanf("%d%d",&n,&m); 62 for(int i=0;i<maxn;i++) 63 w[i].clear(); 64 for(int i=0;i<n;++i) 65 { 66 int x; 67 scanf("%d",&x); 68 //digui(x,i); 69 resolve(x,i); 70 } 71 // for(int i=0;i<maxx;i++) 72 // sort(w,w+w[i].size()); 73 while(m--) 74 { 75 int flag=0,l,r,d; 76 scanf("%d%d%d",&l,&r,&d); 77 l--,r--; 78 for(int i=2;i<=sqrt(d);++i) 79 { 80 int num=0; 81 while(d%i==0) 82 d/=i,num++; 83 if(num) 84 { 85 //upper_bound是找到大于r的 86 //low_bound是找到大于等于l的 87 int pos=upper_bound(w[i].begin(),w[i].end(),r)-lower_bound(w[i].begin() , w[i].end(),l); 88 if(pos < num) //如果小于我们现在需要的,就说明不行。 89 { 90 flag=1; 91 break; 92 } 93 } 94 } 95 if(d>1) //同理 96 { 97 int pos=upper_bound(w[d].begin(),w[d].end(),r)-lower_bound(w[d].begin() , w[d].end(),l); 98 if(pos==0) flag=1; 99 } 100 if(flag) 101 { 102 printf("No\n"); 103 } 104 else 105 { 106 printf("Yes\n"); 107 } 108 } 109 } 110 return 0; 111 }
标签:这一 thml open ret pac www ssis 次数 names
原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12712722.html