• 【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 }
  • 相关阅读:
    Python_Tips[3] -> sort/sorted 排序函数
    Python_Tips[2] -> 函数延后估值及字节码分析
    Python_Tips[1] -> 利用 Python 的字典实现 Switch 功能
    Python_Tips[0] -> 关于 import
    Python与数据库[2] -> 关系对象映射/ORM[4] -> sqlalchemy 的显式 ORM 访问方式
    Python与数据库[2] -> 关系对象映射/ORM[3] -> sqlalchemy 的声明层 ORM 访问方式
    Python与数据库[2] -> 关系对象映射/ORM[2] -> 建立声明层表对象的两种方式
    JS实现网页选取截屏 保存+打印 功能(转)
    nodejs+koa2 实现一个get请求
    windwos下安装使用nginx(转)
  • 原文地址:https://www.cnblogs.com/HLAUV/p/9896107.html
Copyright © 2020-2023  润新知