【问题描述】
给出 n 个数 a1,a2,...,an, 询问有多少个三元组(i, j, k)满足以下两个条件:
1、 i < j < k; 2、 ai*aj*ak 是 p 的倍数。
【输入格式】
第一行两个数 n, p。
接下来一行 n 个数。
【输出格式】
一行一个数表示答案。
【输入样例 1】
4 100
4 5 2 25
【输出样例 1】
2
【输入样例 2】
12 1
1 1 1 1 1 1 1 1 1 1 1 1
【输出样例 2】
220
【输入样例 3】
27 36
269 154 94 221 171 154 50 210 258 358 121 159 8 47 290 125 291 293 338 248 295 160 268
227 99 4 27
【输出样例 3】
145
【数据范围与约定】
对于 30%的数据: n <= 100。
对于 60%的数据: n <= 2000, 1 <= ai <= 10^8。
对于 100%的数据: n <= 30000, 1 <= ai <= 10^8, 1 <= p <= 10^6。
第一眼 好,数论题
第二眼 哦,数据结构来维护
第三眼 额,可以质因数分解?
...
第N眼 靠,怎么做啊?
经过不断的磕磕碰碰,终于往动态规划上想了想,(好,就决定是你了)
前面都是废话
下面是正经部分:
- f[i][j],表示此时我取了1~3元集,与p的最大公约数为j时的方案数。
- 最外层循环i,枚举所有的a[i]
- 倒序从3到1枚举j(想要在自己的身上跳舞就要从身子下方更新上来,不能用脚更新了腰,又把更新后的腰来更新头SMG..)总之如果正序来,会使得已经更新后的值作为前一个a[i-1]的DP值又更新了一次此时的a[i]的DP值。
- 然后用a[i]与p的GCD与枚举的GCD相乘后的结果再与P求一次GCD, 所以此时被更新的状态就是最后求出来的GCD了。
- 当然如果当i==1时,就不需要枚举之前的因子了 直接 f[1][GCD(a[i],p)]++ 就可以了。
几个注意事项:
- 预处理出所有a[i]与p的GCD(不然中间循环算太多次GCD会超时的)
- 看起来DP数组的第二位要开到 p(1000000), 其实不用,我们给p的所有因子编号,开到2*sqrt(p)即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 8 #define For(i,a,b) for(register llg i=a;i<=b;++i) 9 #define Dwn(i,a,b) for(register llg i=a;i>=b;--i) 10 #define llg long long 11 using namespace std; 12 const llg N=3e4+10; 13 llg f[4][2000]; 14 llg yz[N],tot=0; 15 llg a[N],p,n; 16 llg px[1000010]; 17 llg fp[N]; 18 inline void read(llg &v){ 19 v=0; 20 char c=getchar(); 21 while(c<'0'||c>'9')c=getchar(); 22 while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar(); 23 } 24 void Dv(llg x){ 25 llg qx=sqrt(x); 26 For(i,1,qx){ 27 if(x%i==0){ 28 llg y1=i; 29 llg y2=x/i; 30 if(y1!=y2){ 31 yz[++tot]=y1; px[y1]=tot; 32 yz[++tot]=y2; px[y2]=tot; 33 }else{ 34 yz[++tot]=y1; px[y1]=tot; 35 } 36 } 37 } 38 } 39 40 llg Gcd (llg x,llg y){ 41 while(1){ 42 llg yy=x%y; 43 x=y; y=yy; 44 if(yy==0)return x; 45 } 46 } 47 48 int main(){ 49 freopen("divide.in","r",stdin); 50 freopen("divide.out","w",stdout); 51 read(n); read(p); 52 For(i,1,n) read(a[i]); 53 Dv(p); 54 For(i,1,n) fp[i]=Gcd(a[i],p); 55 For(i,1,n){ 56 Dwn(j,3,1){ 57 llg Gx; 58 if(j==1){ 59 Gx=fp[i]; 60 f[1][px[Gx]]+=1; 61 continue; 62 } 63 For(k,1,tot){ 64 if(f[j-1][k]==0)continue; 65 Gx=Gcd(yz[k]*fp[i],p); 66 f[j][px[Gx]]+=f[j-1][k]; 67 } 68 } 69 } 70 71 cout<<f[3][px[p]]<<endl; 72 73 fclose(stdin); fclose(stdout); 74 return 0; 75 }