• Codeforces 980D


    这题其实挺水的,但我比较vegetable,交了好多次才过。

    题意:

    给定一个序列,把这个序列的所有连续子序列分组,每组中任意两个数相乘是个完全平方数,输出每个子序列最少分的组数;

    思路:

    先把每个数都除去自身的完全平方因子,为什么呢?这样处理了之后,只有相同的数相乘才能变成完全平方数,而且原来相乘能变成完全平方数的数对也不会有影响,举个例子:$ 1 imes 4 = 4 $,$4$是完全平方数,除去平方因子后,变成 $1 imes 1 = 1$,$1$还是完全平方数(感性地理解YY一下就好了)

    把处理完的数列从小到大排序,再离散化(防止数字太大,爆MLE)

    由于题目给定n的范围是$5000$,所以不能$ O(n^3) $爆扫,QXZ大佬介绍了一种非常gin的方法,我用了离散化+桶的方法;

    开个桶bo[i][j]表示1到i中数值为j的个数;然后dp,f[i][j]表示i到j的数列需要分成几个区间,f[i][j]=f[i][j-1],当第j个数在i到j中唯一时,f[i][j]++;

    需要注意的点:

    1、除去平方因子时要用while或者倒着扫i,防止有多个平方数;

    2、排序时,要记录原来的位置,离散化完要排列回原来的序列(要按原来给定序列的子序列,而且子序列在原序列中是连续的

    3、0要特判,当0为一个单独的子序列时自成一组,否则与其他任何数都能变成完全平方数(和任何数都能一组

    附上蒟蒻的代码:

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<algorithm>
     4 using namespace std;
     5 const int MAXN=5001;
     6 struct rec
     7 {
     8     int place,num;
     9 }a[MAXN],now;
    10 bool comp1(const rec &x,const rec &y)
    11 {
    12     return x.num<y.num;
    13 }
    14 bool comp2(const rec &x,const rec &y)
    15 {
    16     return x.place<y.place;
    17 }
    18 int n,bo[MAXN][MAXN],f[MAXN][MAXN],ans[MAXN],special0;
    19 bool special[MAXN];
    20 main()
    21 {
    22     scanf("%d",&n);
    23     for(int i=1;i<=n;++i)
    24     {
    25         scanf("%d",&a[i].num);
    26         a[i].place=i;
    27     }
    28     for(int i=1;i<=n;++i)
    29     {
    30         if(a[i].num!=0)
    31         {
    32             int k=sqrt(abs(a[i].num));
    33             for(int j=k;j>=2;--j)
    34             while(a[i].num%(j*j)==0)
    35             {
    36                 a[i].num/=j*j;
    37             }
    38         } else
    39         {
    40             special[i]=true;
    41             special0=i;
    42         }
    43     }
    44     sort(a+1,a+n+1,comp1);
    45     now.place=1;
    46     now.num=a[now.place].num;
    47     a[now.place].num=1;
    48     for(int i=2;i<=n;++i)
    49     {
    50         if(a[i].num==now.num)
    51         {
    52             a[i].num=a[now.place].num;
    53         } else
    54         {
    55             now.place=i;
    56             now.num=a[i].num;
    57             a[i].num=a[i-1].num+1;
    58         }
    59     }
    60     sort(a+1,a+n+1,comp2);
    61     for(int i=1;i<=n;++i)
    62         for(int j=i;j<=n;++j)
    63         bo[j][a[i].num]++;
    64     special0=a[special0].num;
    65     for(int i=1;i<=n;++i)
    66     {
    67         f[i][i]=1;
    68         ++ans[f[i][i]];
    69     }
    70     for(int i=1;i<=n;++i)
    71         for(int j=i+1;j<=n;++j)
    72         {
    73             f[i][j]=f[i][j-1];
    74             if(bo[j][a[j].num]-bo[i-1][a[j].num]==1&&(!special[j])&&(((bo[j][special0]-bo[i-1][special0]!=j-i)||special0==0)))
    75                 ++f[i][j];
    76             ++ans[f[i][j]];
    77         }
    78     for(int i=1;i<=n;++i)
    79         printf("%d ",ans[i]);
    80     return 0;
    81 }
  • 相关阅读:
    LINQ -2015-04-27
    wireshark的安装
    c#中的classes和objects一些知识【1】
    初学C#,用vs去开始hello world!
    file_get_contents HTTP request failed! Internal Server Error
    验证码二(验证码使用)
    接口调用 POST
    接口调用 GET方式
    百度地图改标注样式
    Linux-常用命令
  • 原文地址:https://www.cnblogs.com/JinLeiBo/p/9366437.html
Copyright © 2020-2023  润新知