口算训练
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)Total Submission(s): 359 Accepted Submission(s): 70
Problem Description
小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为
n的正整数序列
a1,a2,...,an,要求小T抛出
m个问题以训练他的口算能力。
每个问题给出三个正整数 l,r,d,小Q需要通过口算快速判断 al×al+1×...×ar−1×ar是不是 d的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
每个问题给出三个正整数 l,r,d,小Q需要通过口算快速判断 al×al+1×...×ar−1×ar是不是 d的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
Input
第一行包含一个正整数
T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含两个正整数 n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含 n个正整数 a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来 m行,每行三个正整数 l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。
每组数据第一行包含两个正整数 n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含 n个正整数 a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来 m行,每行三个正整数 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
Source
Recommend
liuyiding
解题思路:没多想,直接上主席树查询了。对每一个树做质因数分解,然后插入到主席树中,主席树维护质因数个数,然后直接查询数量即可。
踩了一个大坑,主席树每一次Update都要更新根节点……
#include <iostream> #include <algorithm> #include <cstdio> #include <string.h> using namespace std; typedef long long int ll; const int MAXN=100015; typedef pair<int,int> pii; vector<pii> V[MAXN]; void init(){ int cnt; for(int i=2; i<MAXN; i++){ int x = i; for(int j=2; j*j<=x; j++){ cnt = 0; while(x % j == 0){ cnt++; x /= j; } if(cnt){ V[i].push_back(make_pair(j, cnt)); } } if(x > 1){ V[i].push_back(make_pair(x, 1)); } } } int N,Q; int sum[MAXN*400]; int ls[MAXN*400]; int rs[MAXN*400]; int T[MAXN]; int tot=0; void update(int P,int C,int l,int r,int &rt,int lrt){ rt=++tot; ls[rt]=ls[lrt]; rs[rt]=rs[lrt]; sum[rt]=sum[lrt]; if(l==r){ sum[rt]+=C; return; } int m=(l+r)/2; if(P<=m) update(P,C,l,m,ls[rt],ls[lrt]); else update(P,C,m+1,r,rs[rt],rs[lrt]); } int query(int L,int R,int l,int r,int rt,int lrt){ if(L<=l&&r<=R){ return sum[lrt]-sum[rt]; } int m=(l+r)/2; int ans=0; if(L<=m) ans+=query(L,R,l,m,ls[rt],ls[lrt]); if(R>m) ans+=query(L,R,m+1,r,rs[rt],rs[lrt]); return ans; } int main() { init(); int tt; scanf("%d",&tt); while(tt--){ tot=0; memset(sum,0,sizeof(sum)); memset(ls,0,sizeof(ls)); memset(rs,0,sizeof(rs)); int N,M; scanf("%d%d",&N,&M); int a; for(int i=1;i<=N;i++){ scanf("%d",&a); if(a==1) T[i]=T[i-1]; else{ int pre=T[i-1]; for(int j=0;j<V[a].size();j++){ update(V[a][j].first,V[a][j].second,1,MAXN-1,T[i],pre); pre=T[i];//每次都要更新根节点 } } } int l,r,d; while(M--){ scanf("%d%d%d",&l,&r,&d); if(d==1){ printf("Yes\n"); } else{ bool flag=1; for(int j=0;j<V[d].size();j++){ if(query(V[d][j].first,V[d][j].first,1,MAXN-1,T[l-1],T[r])<V[d][j].second) flag=0; } if(flag) printf("Yes\n"); else printf("No\n"); } } } return 0; }