Fork me on GitHub

【NOI广东省选模拟赛】割

【问题描述】

给出 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 }

 

posted @ 2018-11-02 14:31  H_LAUV  阅读(462)  评论(2编辑  收藏  举报
Live2D //博客园自带,可加可不加